Models & context
A chat that lets the user pick the active model and see how much of its context window the conversation has consumed. The model switcher and the token meter both live in <kai-chat>‘s header. Switch models to rescale the window; send a message to watch the meter fill as the reply streams.
How it works
Section titled “How it works”<kai-chat> renders both header controls for you. Set models and currentModel to get the switcher dropdown, set context to get the token meter, and listen for kai-model-change to react to a selection. No separate elements to mount.
<kai-chat id="chat" chat-title="Board prep"></kai-chat>
<script type="module"> import '@kitn.ai/ui/elements';
const chat = document.getElementById('chat');
// Each model has its own context window, so switching rescales the meter. const MAX_TOKENS = { 'claude-opus-4-8': 200_000, 'claude-sonnet-4-6': 1_000_000, 'claude-haiku-4-5': 200_000, };
let modelId = 'claude-opus-4-8'; let usedTokens = 12_400;
// Arrays and objects go in as JS properties, not attributes. chat.messages = []; chat.models = [ { id: 'claude-opus-4-8', name: 'Claude Opus 4.8', provider: 'Anthropic' }, { id: 'claude-sonnet-4-6', name: 'Claude Sonnet 4.6', provider: 'Anthropic' }, { id: 'claude-haiku-4-5', name: 'Claude Haiku 4.5', provider: 'Anthropic' }, ]; chat.currentModel = modelId;
function pushContext() { // Reassign a fresh object so the meter re-renders. chat.context = { usedTokens, maxTokens: MAX_TOKENS[modelId], inputTokens: Math.round(usedTokens * 0.62), outputTokens: Math.round(usedTokens * 0.38), }; } pushContext();
// Selecting a model swaps the active label and rescales the window. chat.addEventListener('kai-model-change', (e) => { modelId = e.detail.modelId; chat.currentModel = modelId; pushContext(); });
chat.addEventListener('kai-submit', async (e) => { const aId = crypto.randomUUID(); chat.messages = [ ...chat.messages, { id: crypto.randomUUID(), role: 'user', content: e.detail.value }, { id: aId, role: 'assistant', content: '' }, ]; chat.loading = true;
// Stream the reply and grow usedTokens as output arrives. for await (const token of streamReply(e.detail.value, modelId)) { chat.messages = chat.messages.map((m) => m.id === aId ? { ...m, content: m.content + token } : m, ); usedTokens += estimateTokens(token); pushContext(); }
chat.loading = false; });</script>The switcher only renders when you provide more than one model. The meter turns yellow once usage crosses warnThreshold (default 70%) and red past dangerThreshold (default 90%) — handy for warning users before a long thread overflows the window.
context shape — the usage object you assign to chat.context:
| field | type | notes |
|---|---|---|
usedTokens | number | Tokens consumed so far — drives the meter fill |
maxTokens | number | The model’s full context window |
inputTokens | number? | Prompt tokens, shown in the hover breakdown |
outputTokens | number? | Generated tokens, shown in the hover breakdown |
estimatedCost | number? | Running cost in dollars, shown in the footer |
Next steps
Section titled “Next steps”kai-chatreference — every header prop, includingmodels,currentModel, andcontext.kai-model-switcherreference — the standalone switcher with amodelsproperty or declarative<kai-model>children.kai-contextreference — the standalone meter, configurablewarnThreshold/dangerThreshold, and thekai-threshold-changeevent.- Drop-in chat — the baseline streaming loop this example extends.