93 / 122 · Thread
Connection state
The socket drops, the run keeps going on the server, and the stream is picked back up.
Installation
npx shadcn@latest add "@assistant-ui/elements-connection-state"
Usage
import { ConnectionState } from "@/components/elements/connection-state";
<ConnectionState phase="reconnecting" attempt={2} onRetry={reconnect} />Props
phase*"online" | "dropped" | "reconnecting" | "resumed"Which banner to show. online renders nothing, so the element can stay mounted.
attemptnumberRetry number, shown while reconnecting.
resumedTokensnumberHow much of the stream was recovered, shown once resumed.
onRetry() => voidCalled from the Reconnect button while dropped.
classNamestringExtra classes merged onto the root.
Source
connection-state.tsx"use client";
import { CheckIcon, CloudOffIcon, Loader2Icon } from "lucide-react";
import { cn } from "@/lib/utils";
import { mono, paper } from "./surfaces";
export type ConnectionPhase = "online" | "dropped" | "reconnecting" | "resumed";
export function ConnectionState({
phase,
attempt,
resumedTokens,
onRetry,
className,
}: {
phase: ConnectionPhase;
attempt?: number;
resumedTokens?: number;
onRetry?: () => void;
className?: string;
}) {
if (phase === "online") return null;
return (
<div
className={cn(
paper,
"fade-in slide-in-from-top-1 animate-in flex w-full max-w-sm items-center gap-2.5 rounded-2xl px-3.5 py-2.5 duration-300",
className,
)}
>
{phase === "dropped" && (
<>
<CloudOffIcon className="size-3.5 shrink-0 text-amber-600 dark:text-amber-400" />
<span className="min-w-0 flex-1 text-[13px]">
Connection lost. The run kept going on the server.
</span>
<button
type="button"
onClick={onRetry}
className="text-foreground/70 hover:bg-foreground/[0.06] hover:text-foreground/95 shrink-0 rounded-full px-2.5 py-1 text-xs font-medium transition-[background-color,color,scale] duration-150 active:scale-[0.96]"
>
Reconnect
</button>
</>
)}
{phase === "reconnecting" && (
<>
<Loader2Icon className="text-foreground/40 size-3.5 shrink-0 animate-spin motion-reduce:animate-none" />
<span className="min-w-0 flex-1 text-[13px]">Reconnecting</span>
{attempt !== undefined && (
<span
className={cn(mono, "text-foreground/30 shrink-0 tabular-nums")}
>
attempt {attempt}
</span>
)}
</>
)}
{phase === "resumed" && (
<>
<CheckIcon className="size-3.5 shrink-0 text-emerald-500" />
<span className="min-w-0 flex-1 text-[13px]">
Picked the stream back up.
</span>
{resumedTokens !== undefined && (
<span
className={cn(mono, "text-foreground/30 shrink-0 tabular-nums")}
>
+{resumedTokens} tokens
</span>
)}
</>
)}
</div>
);
}