TrademarkTrademark
Ctrl k
Search docs...
Guides
Surfaces

AI chat

An agent chat that runs on a scripted mock, with two interfaces between it and a real model and database.
The chat surface is the interface of an AI assistant: a sidebar of chats grouped into pinned, projects and recents, a conversation where agent steps and widgets stream in, and a resizable context panel with the run timeline, the widgets and the chat's settings. Below the desktop breakpoint the panels become drawers. It serves /chat and requires no slices. Chats live in localStorage and answers come from a mock model in the browser, so it runs on zero environment variables and no API key. Without the landing surface, / redirects to /chat. Everything the UI needs from outside goes through two interfaces in src/lib/chat, and the hook that drives the UI, useChats, reads only them. Where chats live is ChatStore, in store.ts: It ships as localChatStore, seeded with sample chats. Keeping chats in a database, per user or per organization, is a new object with this shape assigned to chatStore in the same file. Where answers come from is ChatModel, in model.ts: stream yields ChatEvents: text deltas, steps (a step sent again with the same id updates it), widgets, and a final usage with the tokens the answer used. The surface ships mockModel, which plays canned agent runs picked by what the message is about, and quickModel, the same without steps. stream runs in the browser, so a real model is an API route that calls your provider with its key, plus a ChatModel whose stream fetches that route and turns the provider's stream into ChatEvents: text as deltas, tool calls as steps, structured output as widgets. Add it to the models array in model.ts and it appears in the model picker; the UI does not change. The surface itself ships no route and no provider SDK. Widgets are a closed union in types.ts: tasks, chart and sources. A new kind is a new member there and a new case in src/app/(chat)/components/Widgets.tsx. The daily allowance in the usage meter is DAILY_TOKEN_LIMIT, a constant in model.ts, and each model's rate says how much of it one token costs. Every chat and project carries a ChatTheme: a brand, an accent and a neutral from Once UI's own palette. ChatThemeScope applies it to the chat's subtree as data-brand, data-accent and data-neutral, so every component inside takes the chat's colors without a prop. A chat nobody has themed by hand follows its project, including when it is moved into one; outside a project, autoTheme picks a stable theme from the chat's id. Picking colors in the theme dialog makes them the chat's own. The chat building blocks in src/app/(chat)/components/kit are a copy of Once UI core's chat components, kept here until the core release that exports them is published.
Last updated October 18, 2026
Edit this page on GitHub