1<script lang="ts">
2 import * as AlertDialog from '$lib/components/ui/alert-dialog';
3 import { AlertTriangle, TimerOff } from '@lucide/svelte';
4
5 interface Props {
6 open: boolean;
7 type: 'timeout' | 'server';
8 message: string;
9 contextInfo?: { n_prompt_tokens: number; n_ctx: number };
10 onOpenChange?: (open: boolean) => void;
11 }
12
13 let { open = $bindable(), type, message, contextInfo, onOpenChange }: Props = $props();
14
15 const isTimeout = $derived(type === 'timeout');
16 const title = $derived(isTimeout ? 'TCP Timeout' : 'Server Error');
17 const description = $derived(
18 isTimeout
19 ? 'The request did not receive a response from the server before timing out.'
20 : 'The server responded with an error message. Review the details below.'
21 );
22 const iconClass = $derived(isTimeout ? 'text-destructive' : 'text-amber-500');
23 const badgeClass = $derived(
24 isTimeout
25 ? 'border-destructive/40 bg-destructive/10 text-destructive'
26 : 'border-amber-500/40 bg-amber-500/10 text-amber-600 dark:text-amber-400'
27 );
28
29 function handleOpenChange(newOpen: boolean) {
30 open = newOpen;
31 onOpenChange?.(newOpen);
32 }
33</script>
34
35<AlertDialog.Root {open} onOpenChange={handleOpenChange}>
36 <AlertDialog.Content>
37 <AlertDialog.Header>
38 <AlertDialog.Title class="flex items-center gap-2">
39 {#if isTimeout}
40 <TimerOff class={`h-5 w-5 ${iconClass}`} />
41 {:else}
42 <AlertTriangle class={`h-5 w-5 ${iconClass}`} />
43 {/if}
44
45 {title}
46 </AlertDialog.Title>
47
48 <AlertDialog.Description>
49 {description}
50 </AlertDialog.Description>
51 </AlertDialog.Header>
52
53 <div class={`rounded-lg border px-4 py-3 text-sm ${badgeClass}`}>
54 <p class="font-medium">{message}</p>
55 {#if contextInfo}
56 <div class="mt-2 space-y-1 text-xs opacity-80">
57 <p>
58 <span class="font-medium">Prompt tokens:</span>
59 {contextInfo.n_prompt_tokens.toLocaleString()}
60 </p>
61 <p><span class="font-medium">Context size:</span> {contextInfo.n_ctx.toLocaleString()}</p>
62 </div>
63 {/if}
64 </div>
65
66 <AlertDialog.Footer>
67 <AlertDialog.Action onclick={() => handleOpenChange(false)}>Close</AlertDialog.Action>
68 </AlertDialog.Footer>
69 </AlertDialog.Content>
70</AlertDialog.Root>