useStreamingMessage

Per-message helper for chat UIs. Given a chat from useAIChat and a target message id, derives 'is this one still streaming?' plus abort/retry handles. Use to wire a LoadingIndicator into a single message bubble, or to expose a retry button on the last assistant turn. Pure selector — no DOM, no extra state.

Installation

pnpm
pnpm dlx @hex-core/cli add use-streaming-message

Usage

tsx
import { useStreamingMessage } from "@/components/ui/use-streaming-message"

Loading indicator per bubble

Show a streaming indicator inside the message that's currently being generated.

tsx
import { useAIChat, useStreamingMessage, Message, LoadingIndicator } from "@hex-core/components";

function Bubble({ chat, messageId }) {
  const { message, isStreaming } = useStreamingMessage(chat, messageId);
  if (!message) return null;
  return (
    <Message role={message.role}>
      {message.content}
      {isStreaming ? <LoadingIndicator variant="dots" /> : null}
    </Message>
  );
}

API Reference

PropTypeDefaultDescription
chatrequired
objectUseAIChatReturn — the value from useAIChat() (or any adapter returning the same shape).
messageIdrequired
stringThe id of the message to introspect. Returns isStreaming: false when no message matches.

AI Guidance

When to use

Use inside a per-message component when you need to know whether THIS message is the one currently streaming, or to expose abort/retry tied to a specific bubble. Avoids re-implementing 'find the last assistant message' across the codebase.

When not to use

Don't use as the single source of chat state — that's useAIChat's job. Don't use to check chat status broadly; just read chat.status directly.

Common mistakes

  • Expecting isStreaming to be true for every assistant message — it's only true for the LAST assistant message while chat is submitted/streaming.
  • Calling retry() mid-stream — it triggers regenerate on the SDK which aborts the current stream and restarts. Disable the retry button while isStreaming is true.

Accessibility

No DOM output — wire isStreaming into a <LoadingIndicator label='Generating response'/> so screen readers announce the state.

Token budget: 633

Verified against @hex-core/components@1.14.0