Skip to content
kitn AI/UI

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.

<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:

fieldtypenotes
usedTokensnumberTokens consumed so far — drives the meter fill
maxTokensnumberThe model’s full context window
inputTokensnumber?Prompt tokens, shown in the hover breakdown
outputTokensnumber?Generated tokens, shown in the hover breakdown
estimatedCostnumber?Running cost in dollars, shown in the footer
  • kai-chat reference — every header prop, including models, currentModel, and context.
  • kai-model-switcher reference — the standalone switcher with a models property or declarative <kai-model> children.
  • kai-context reference — the standalone meter, configurable warnThreshold / dangerThreshold, and the kai-threshold-change event.
  • Drop-in chat — the baseline streaming loop this example extends.