AI
What knows a model is on the other end — Tasks, where a small model fills an artefact that oracles check; a field the model helps fill; a conversation, with data or without — over the AI SDK, reached through @kanzo-tech/llm, a model in the page. A sibling of @kanzo-tech/ui, never part of it.
@kanzo-tech/ai ships one pattern and the surfaces built on it, one door each:
| For | Page | |
|---|---|---|
defineTask + runTask + useTask | A Task: a small model fills a small artefact under a schema or a grammar, oracles that are facts check it, and a bounded loop repairs it or asks the person — @kanzo-tech/ai/task | Tasks |
AssistProvider + Assist | A field the model helps fill: ghost text in a Textarea, whole values under an Input, items for a TagsInput | Assist |
Chat + useAgentChat | A conversation, whole: transcript, streaming markdown, reasoning, tool calls, the composer | Chat |
Working, ModelBadge, Checkpoint, ChainOfThought, Sources | A conversation whose turns are the host's, from Chat's parts and these: work under way, a model in the page as it loads, a point to go back to, the steps of the work, the sources a thread rests on — and @kanzo-tech/ui's Question for a decision | A guided chat |
useAskChat + AnswerCard | A conversation with data: Ask, which answers with a dashboard tile over a relation of the page's DuckDB, and the card each answer is drawn in — @kanzo-tech/ai/data | Ask your data |
Chat is the door, and it is the whole conversation wired: five compounds a host used to assemble
by hand became one. The parts it draws with — the scrolling transcript, the message, the tool frame,
the reasoning fold, the composer — are exported beside it, for a transcript that is not Chat's: an
agent's log, a review pane, a guided conversation whose turns are the host's. They were internal
until a host needed them one at a time, which is the evidence that reverses wire them for
everyone: a part with a second arrangement is a part. The transcript and the composer came out
last, when keasy's guided chat drew both by hand — the scroll as an effect that follows every turn,
the composer from InputGroup with Enter wired again. The ✨ stays internal, since nothing draws it
but Assist, and would come out the same way. The parts lists them.
The model behind all of them is the AI SDK's, asked through
@kanzo-tech/llm's two doors — in the page, on WebGPU.
The SDK's own names a host imports from ai.
Why it is not in the library
The line is not is it AI. It is does the component know a model exists. A Button does not,
and a Collapsible does not — which is why the transcript is built from both and neither moved.
Assist takes a model; Chat draws parts whose role is assistant. That is domain knowledge, and
the first admission rule keeps the generic vocabulary free of it.
The blunter reason is that the root barrel is a one-way door: a consumer who wants a Button
must not pay for a transcript. A separate package makes that structural. It depends on
@kanzo-tech/ui; nothing in ui may depend on it.
Installing it
pnpm add @kanzo-tech/ai @kanzo-tech/llm ai @ai-sdk/reactIts other peers, all required:
pnpm add @kanzo-tech/ui @ark-ui/react react react-dom lucide-reactai and @ai-sdk/react are peers rather than dependencies for the reason
@kanzo-tech/llm gives: the host's agent and these components
must share one UIMessage, one transport and one useChat, and two copies of the SDK are two type
universes that do not assign to each other. @kanzo-tech/ui and Ark are peers because two copies of
Ark are two portals and two focus traps. streamdown, which draws the markdown, is a dependency:
nothing outside Chat names it.
@kanzo-tech/ai/data is a subpath for the reason /analytics is one in @kanzo-tech/ui: it draws
with the analytics and table layers, whose engines are optional peers, and a host that only
chats must not install DuckDB to import Chat. Ask your data has its peers.
The stylesheet is one line after @kanzo-tech/ui's — @import "@kanzo-tech/ai/tailwind.css" — and
carries sources only: the tokens and variants are ui's.
The middleware pattern
@kanzo-tech/llm holds what the AI SDK lacks and none of what it has: the third party is a
required peer, imported by name, and what is ours is the door it does not have — stream and
generate, each asking once, and localModel, a model in the page. Three layers:
@kanzo-tech/ai Assist, Chat, useAgentChat React; draws
@kanzo-tech/llm stream, generate, localModel no React; every model call, once
ai, @ai-sdk/react the AI SDK: agents, tools, types installed once, imported by nameSo a host's AI imports are a few lines:
import { localModel } from "@kanzo-tech/llm/local";
import { ToolLoopAgent, tool } from "ai";
import { Assist, AssistProvider, Chat, useAgentChat } from "@kanzo-tech/ai";What it does not do
- It does not choose a model. A model is a
LanguageModelthe host passes in —localModel, in the page, or the double in a test.Assistasks whateverAssistProvideris given;Chatdraws whatever its agent streams. - It does not persist anything. The conversation is the AI SDK's chat state, and a field's value is the host's own state.
Assist
One proposal for a field, drawn as ghost text or as chips.
Chat
A conversation with a model, whole, with the host's tools drawn inside it.
Ask your data
An agent that answers with a dashboard tile over the page's data, and the card each answer is drawn in.
@kanzo-tech/llm
stream and generate, each asking once; localModel; and the model double.
Benchmarks
Our viewer against cosmos.gl alone on the same positions, how far cosmos.gl's live layout goes, and where the layout's tuning was measured.
Assist
A field the model helps fill. One proposal for the field's value, drawn the way the control calls for — ghost text at the caret of a Textarea, whole values under an Input, items for a TagsInput.