AI Elements
Model Selector
Two menus. One picks the model the agent runs, the other picks how hard it thinks.
Installation
Model Selector is built with the Dropdown Menu and Input Group components.
Usage
<template>
<UiInputGroup>
<UiInputGroupTextarea placeholder="Ask the agent to change your code..." />
<UiInputGroupAddon align="block-end">
<UiDropdownMenu>
<UiDropdownMenuTrigger as-child>
<UiInputGroupButton size="sm">
GPT-5
<UiIcon name="lucide:chevron-down" />
</UiInputGroupButton>
</UiDropdownMenuTrigger>
<UiDropdownMenuContent align="start">
<UiDropdownMenuRadioGroup v-model="model">
<UiDropdownMenuGroup>
<UiDropdownMenuLabel>OpenAI</UiDropdownMenuLabel>
<UiDropdownMenuRadioItem value="gpt-5"> GPT-5 </UiDropdownMenuRadioItem>
<UiDropdownMenuRadioItem value="gpt-5-mini"> GPT-5 mini </UiDropdownMenuRadioItem>
</UiDropdownMenuGroup>
</UiDropdownMenuRadioGroup>
</UiDropdownMenuContent>
</UiDropdownMenu>
<UiDropdownMenu>
<UiDropdownMenuTrigger as-child>
<UiInputGroupButton size="sm">
Medium
<UiIcon name="lucide:chevron-down" />
</UiInputGroupButton>
</UiDropdownMenuTrigger>
<UiDropdownMenuContent align="start">
<UiDropdownMenuRadioGroup v-model="effort">
<UiDropdownMenuRadioItem value="low"> Low </UiDropdownMenuRadioItem>
<UiDropdownMenuRadioItem value="medium"> Medium </UiDropdownMenuRadioItem>
<UiDropdownMenuRadioItem value="high"> High </UiDropdownMenuRadioItem>
</UiDropdownMenuRadioGroup>
</UiDropdownMenuContent>
</UiDropdownMenu>
<UiInputGroupButton type="submit" variant="default" class="ml-auto">
<UiIcon name="lucide:arrow-up" />
</UiInputGroupButton>
</UiInputGroupAddon>
</UiInputGroup>
</template>
<script lang="ts" setup>
const model = ref("gpt-5");
const effort = ref("medium");
</script>
AI SDK
Send the model and the effort with the message. Map them to a model and provider options in the route.
chat.sendMessage({ text }, { body: { model: model.value, effort: effort.value } });
import { anthropic } from "@ai-sdk/anthropic";
import { openai } from "@ai-sdk/openai";
import type { UIMessage } from "ai";
import { convertToModelMessages, streamText } from "ai";
const models = {
"gpt-5": openai("gpt-5"),
"gpt-5-mini": openai("gpt-5-mini"),
"claude-sonnet-4-5": anthropic("claude-sonnet-4-5"),
"claude-haiku-4-5": anthropic("claude-haiku-4-5"),
};
export default defineEventHandler(async (event) => {
const { messages, model, effort } = await readBody<{
messages: UIMessage[];
model: keyof typeof models;
effort: "low" | "medium" | "high";
}>(event);
const result = streamText({
model: models[model] ?? models["gpt-5"],
messages: await convertToModelMessages(messages),
providerOptions: {
openai: { reasoningEffort: effort },
anthropic: { effort },
},
});
return result.toUIMessageStreamResponse();
});
Each provider reads its own key in providerOptions and ignores the rest.