Owned types
The package defines its own structural message types — and the AI SDK's UIMessage satisfies them for free.
The components read messages through types the package owns, in
@intentface/chat/types — ChatMessage, MessagePart and its variants
(TextPart, ReasoningPart, ToolPart, …), and ChatStatus. The package has
no dependency on the AI SDK; its only peer is React.
Structural, not nominal
The types are defined so that the AI SDK's UIMessage satisfies them
structurally — no adapter, no mapping layer. A UIMessage's parts already have
the shape ChatMessage describes, so you pass your SDK messages straight in and
they typecheck.
import type { ChatMessage } from "@intentface/chat/types";
import type { UIMessage } from "ai";
// The app's message type flows into the components unchanged.
type AppMessage = UIMessage<{ stopped?: boolean }>;
const messages: ChatMessage[] = appMessages; // structurally assignableThe app keeps a compile-time assertion that its UIMessage still satisfies
ChatMessage, so an AI SDK upgrade that broke the shape would fail typecheck
loudly rather than silently.
Extend by generic
ChatMessage<Metadata, Part> takes your metadata and part types as generics, so
custom parts and metadata carry through the helpers:
type MyMessage = ChatMessage<{ stopped?: boolean }, MyPart>;Not the AI SDK
Because the contract is structural, the package works with any source that produces the same shape — a different framework, a raw API, your own store. The AI SDK is the common case, not a requirement, and it never appears in the package's dependency graph.