feat: Show agent errors in chat UI with retry button
When the chat agent crashes (e.g., expired OAuth token), display the error message inline with a Retry button that re-sends the last user message. Input stays enabled so users can also send a new message.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { motion, AnimatePresence } from 'motion/react';
|
||||
import { X, Loader2 } from 'lucide-react';
|
||||
import { X, Loader2, AlertTriangle, RotateCcw } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useChatSession } from '@/hooks/useChatSession';
|
||||
import { ChatBubble } from './ChatBubble';
|
||||
import { ChatInput } from './ChatInput';
|
||||
@@ -41,7 +42,7 @@ function ChatSlideOverInner({
|
||||
initiativeId: string;
|
||||
onClose: () => void;
|
||||
}) {
|
||||
const { messages, agentStatus, sendMessage, closeSession, isSending } =
|
||||
const { messages, agentStatus, agentError, sendMessage, closeSession, isSending } =
|
||||
useChatSession(target.type, target.id, initiativeId);
|
||||
|
||||
const scrollRef = useRef<HTMLDivElement>(null);
|
||||
@@ -130,6 +131,32 @@ function ChatSlideOverInner({
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{agentStatus === 'crashed' && agentError && (
|
||||
<div className="mx-4 my-2 rounded-lg border border-status-error-border bg-status-error-bg px-3 py-2.5">
|
||||
<div className="flex items-start gap-2">
|
||||
<AlertTriangle className="mt-0.5 h-3.5 w-3.5 shrink-0 text-status-error-fg" />
|
||||
<div className="min-w-0 flex-1">
|
||||
<p className="text-xs font-medium text-status-error-fg">Agent error</p>
|
||||
<p className="mt-0.5 text-xs text-status-error-fg/80 break-words">{agentError}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-2 flex justify-end">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="h-6 gap-1.5 text-xs"
|
||||
onClick={() => {
|
||||
// Re-send the last user message to retry
|
||||
const lastUserMsg = [...messages].reverse().find(m => m.role === 'user');
|
||||
if (lastUserMsg) sendMessage(lastUserMsg.content);
|
||||
}}
|
||||
>
|
||||
<RotateCcw className="h-3 w-3" />
|
||||
Retry
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Input */}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { toast } from 'sonner';
|
||||
import { trpc } from '@/lib/trpc';
|
||||
import { useLiveUpdates } from './useLiveUpdates';
|
||||
|
||||
export type ChatAgentStatus = 'idle' | 'running' | 'waiting' | 'none';
|
||||
export type ChatAgentStatus = 'idle' | 'running' | 'waiting' | 'crashed' | 'none';
|
||||
|
||||
export interface ChatMessage {
|
||||
id: string;
|
||||
@@ -28,6 +28,7 @@ export interface UseChatSessionResult {
|
||||
session: ChatSession | null;
|
||||
messages: ChatMessage[];
|
||||
agentStatus: ChatAgentStatus;
|
||||
agentError: string | null;
|
||||
sendMessage: (message: string) => void;
|
||||
closeSession: () => void;
|
||||
isSending: boolean;
|
||||
@@ -88,11 +89,26 @@ export function useChatSession(
|
||||
return 'waiting';
|
||||
case 'idle':
|
||||
return 'idle';
|
||||
case 'crashed':
|
||||
return 'crashed';
|
||||
default:
|
||||
return 'none';
|
||||
}
|
||||
}, [session?.agentId, agentQuery.data]);
|
||||
|
||||
// Extract error message when agent crashed
|
||||
const agentError = useMemo(() => {
|
||||
if (agentStatus !== 'crashed' || !agentQuery.data) return null;
|
||||
const result = (agentQuery.data as { result?: string }).result;
|
||||
if (!result) return 'Agent crashed unexpectedly';
|
||||
try {
|
||||
const parsed = JSON.parse(result);
|
||||
return parsed.message ?? result;
|
||||
} catch {
|
||||
return result;
|
||||
}
|
||||
}, [agentStatus, agentQuery.data]);
|
||||
|
||||
// Send message mutation
|
||||
const sendMutation = trpc.sendChatMessage.useMutation({
|
||||
onSuccess: () => {
|
||||
@@ -161,6 +177,7 @@ export function useChatSession(
|
||||
session,
|
||||
messages,
|
||||
agentStatus,
|
||||
agentError,
|
||||
sendMessage,
|
||||
closeSession,
|
||||
isSending,
|
||||
|
||||
Reference in New Issue
Block a user