AI Chat TypeScript helper for React
v1.0.0Added in 1.0.0
The AI kit's shared vocabulary: message, tool call and model types, token and duration formatting, live timers and a mock stream.
Press Generate to stream a fake answer through mockStream: the text arrives word by word (or letter by letter with chunk char), the token estimate grows, and the elapsed time ticks in formatDuration and formatTimer. Stop aborts the stream through its signal. Below, the capability icons and the tool-call status tones every AI component uses.
AI Chat is a Pro React helper in the React hooks and utilities category, written in TypeScript for React 19. It installs as source with npx wingo-ui@latest add ai-chat, together with Number format, Relative time and Tones and the npm package lucide-react.
Add to a project
Requirements: React 19, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup
npx wingo-ui@latest add ai-chatAI Chat is part of Pro, with 298 more Pro items: $8 a month or $150 once. 14-day refund before you download any Pro item. See plans
Usage
Import mockStream from @/lib/ai-chat.
"use client"
import { useState } from "react"
import { estimateTokens, formatTokens, mockStream } from "@/lib/ai-chat"
import { Button } from "@/components/ui/button"
export function FakeAnswer() {
const [text, setText] = useState("")
const generate = async () => {
setText("")
for await (const delta of mockStream("You have 3 overdue invoices, $22,775.95 in total.")) setText((t) => t + delta)
}
return (
<div className="flex flex-col gap-3">
<Button onClick={generate}>Generate</Button>
<p>{text}</p>
<span className="text-xs text-muted-foreground">{formatTokens(estimateTokens(text), "en-US")} tokens</span>
</div>
)
}API
delaydefault28numbermockStream(text, { delay, chunk, firstDelay = 350, signal }): an async generator that yields text in chunks every `delay` ms, like a model streaming. for await (const delta of mockStream(answer, { signal })) setText((t) => t + delta). Aborting the signal ends it.
chunkdefault"word""word" | "char"mockStream: whole words with their spaces (how models stream) or one character at a time.
localedefault"en-US"stringThe locale passed to formatTokens and formatDuration in the demo (every formatter takes one).
compactdefaulttruebooleanformatTokens(count, locale?, { compact = true }): 812, "12.5K", "1.3M" in en-US; compact false writes every digit ("12,480").
ChatMessageData{ id; role: ChatRole; content: string; status?: ChatStatus; createdAt?; author?: ChatPerson; model?; attachments?: ChatAttachment[]; reasoning?: ChatReasoning; toolCalls?: ToolCall[]; sources?: ChatSource[]; error?; feedback?: ChatFeedback; edited?; branch?: { index; count } }One message of a conversation; content is markdown. ChatRole = "user" | "assistant" | "system"; ChatStatus = "pending" | "streaming" | "complete" | "stopped" | "error"; ChatFeedback = "up" | "down" | null. ChatAttachment = { id; name; type?; size?; url?; previewUrl?; status?: "uploading" | "ready" | "error"; progress? (0..1); error? }. ChatSource = { id; title; url?; snippet?; favicon? }. ChatReasoning = { content; status?; startedAt?; endedAt?; durationMs? }. ChatPerson = { id; name; avatar? }.
ToolCall{ id; name; title?; description?; status: ToolCallStatus; input?; output?; error?; startedAt?; endedAt?; durationMs?; logs?: string[]; steps?: ToolCall[] }One tool call or agent step. ToolCallStatus = "pending" | "running" | "complete" | "error" | "canceled" | "awaiting-approval". TOOL_CALL_STATUS_TONES maps them to tones (neutral, info, success, danger, neutral, warning) and DEFAULT_TOOL_CALL_STATUS_LABELS to English words. getToolCallTitle(call) and humanizeToolName("search_invoices") give "Search invoices"; summarizeToolCalls(calls) counts total / running / complete / error / pending / awaiting, sub-steps included; stringifyToolValue(value) prints inputs and outputs (strings as they are, the rest as indented JSON).
AiModel{ id; name; provider?; description?; icon?; group?; capabilities?: AiCapability[]; contextWindow?; speed?: 1 | 2 | 3; cost?: 1 | 2 | 3; pricing?: { input; output; currency? }; badge?: { label; tone? }; recommended?; isNew?; disabled?; disabledReason?; keywords? }A model for pickers. AiCapability = "vision" | "tools" | "reasoning" | "web" | "files" | "code" | "image" | "voice", with AI_CAPABILITIES (the order), AI_CAPABILITY_ICONS (lucide) and DEFAULT_AI_CAPABILITY_LABELS. Pricing is per 1M tokens.
ChatSuggestion{ id; label; prompt?; description?; icon?; group? }A suggested prompt; prompt defaults to label.
estimateTokens(text: string) => numberA fast estimate for hints and meters: about 4 characters per token for Latin text, one per CJK character. Real counts come from the provider.
formatDuration(ms: number, { locale?, style?: "long" | "short" | "narrow" }) => string"2.4 sec", "42 sec", "2 min, 5 sec", "1 hr, 12 min" in en-US: tenths below 10 s, then at most two whole units, through Intl unit formatting.
formatTimer(ms: number) => stringA stopwatch: "0:42", "12:05", "1:02:03" (recordings, an agent's run time).
getElapsed({ startedAt?, endedAt?, durationMs? }, now?) => number | nullms of a reasoning block, tool call or run: durationMs if given, else end (or now while running) minus start; null when the start is unknown.
useTicker(running: boolean, interval = 1000) => number | nullA clock for live timers that ticks only while running and shares one interval per step across components. null on the server and during hydration (show nothing or the final duration), then Date.now() rounded to the step.
createChatId(prefix = "msg") => stringA unique id for messages, attachments and calls created in the browser. Call it in handlers, never during render.
Examples
Agent steps
A tool call list with status tones, durations and a summary header, built only from the kit's helpers and types.
Dependencies
Files
- lib/ai-chat.ts
FAQ
Is the AI Chat helper free?
The preview, props and docs are free; copying the source needs a Pro plan. See plans.
How do I install AI Chat?
Run npx wingo-ui@latest add ai-chat. It also adds the Wingo UI items it builds on (Number format, Relative time and Tones) and the npm package lucide-react. With shadcn, add the @wingo-ui registry with your API key, then run npx shadcn@latest add @wingo-ui/ai-chat.