Connect any model
AI/UI doesn’t care which model answers. Point it at OpenAI, Anthropic, Grok, GLM, DeepSeek, Llama — anything — and let people switch between them from a dropdown in the chat header. Open the model menu below and pick a different provider.
One endpoint, every model
Section titled “One endpoint, every model”The switch isn’t AI/UI’s doing — it’s the gateway’s. A gateway like OpenRouter or Vercel AI Gateway puts one OpenAI-compatible endpoint in front of hundreds of models and routes by id. Change model from openai/gpt-4o to x-ai/grok-2 and the same request lands on a different model. Your server route never changes:
// app/api/chat/route.ts — forward the user's chosen model to the gatewayexport async function POST(req: Request) { const { model, messages } = await req.json();
const upstream = await fetch('https://openrouter.ai/api/v1/chat/completions', { method: 'POST', headers: { Authorization: `Bearer ${process.env.OPENROUTER_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ model, messages, stream: true }), });
// The gateway returns OpenAI-format SSE — stream it straight back to the browser. return new Response(upstream.body, { headers: { 'Content-Type': 'text/event-stream' } });}On the front end, the switcher is built into <kai-chat>: set models, listen for kai-model-change, and send the current id with each request.
<kai-chat id="chat"></kai-chat>
<script type="module"> import '@kitn.ai/ui/elements';
await customElements.whenDefined('kai-chat');
const chat = document.getElementById('chat');
let model = 'openai/gpt-4o'; chat.models = [ { id: 'openai/gpt-4o', name: 'GPT-4o', provider: 'OpenAI' }, { id: 'x-ai/grok-2', name: 'Grok', provider: 'xAI' }, { id: 'z-ai/glm-4.6', name: 'GLM', provider: 'Zhipu' }, { id: 'deepseek/deepseek-chat', name: 'DeepSeek', provider: 'DeepSeek' }, ]; chat.currentModel = model; chat.addEventListener('kai-model-change', (e) => { model = e.detail.modelId; });
chat.addEventListener('kai-submit', async (e) => { // append the user + empty assistant message, then call your route with `model` await fetch('/api/chat', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ model, messages: chat.messages }), }); // stream the reply into messages — see the Streaming recipe });</script>Gateways vs direct providers
Section titled “Gateways vs direct providers”There are two ways to reach a model, and both run the route above unchanged.
Gateways put hundreds of models behind one OpenAI-compatible endpoint, with routing, fallbacks, and spend tracking. Swap the base URL and key; the code is identical.
| Gateway | Base URL | Example model ids |
|---|---|---|
| OpenRouter | https://openrouter.ai/api/v1 | openai/gpt-4o, x-ai/grok-2, z-ai/glm-4.6 |
| Vercel AI Gateway | https://ai-gateway.vercel.sh/v1 | openai/gpt-4o, anthropic/claude-... |
| Cloudflare AI Gateway | per-account URL | passthrough to the upstream provider |
Direct providers skip the gateway when you only need one vendor. Most ship an OpenAI-compatible endpoint, so the same route works — only the base URL, key, and id change.
| Provider | OpenAI-compatible base URL |
|---|---|
| OpenAI | https://api.openai.com/v1 |
| xAI (Grok) | https://api.x.ai/v1 |
| Zhipu (GLM) | https://open.bigmodel.cn/api/paas/v4 |
| DeepSeek | https://api.deepseek.com |
| Groq | https://api.groq.com/openai/v1 |
| Ollama (local) | http://localhost:11434/v1 |
Next steps
Section titled “Next steps”- Connect any backend — the
messagescontract this builds on. - Streaming — the reader loop that pulls the reply into the thread.
- Harnesses — when the backend is a full agent, not just a model.