React UI
Composer controls
Add app-owned model selectors, reasoning controls, and custom submit behavior to @anvia/react-ui composers.
Model selection, reasoning effort, temperature, provider choice, and similar controls belong to
application state. Render those controls inside Composer.Root when they are part of the prompt
bar, then include their values in useChat({ createRequest }).
import type { Message } from "@anvia/core/completion";
import { useChat } from "@anvia/react";
import { ChatProvider, Composer } from "@anvia/react-ui";
import { useState } from "react";
type ReasoningEffort = "low" | "medium" | "high";
type ChatRequest = {
messages: Message[];
stream: true;
model: string;
reasoning: { effort: ReasoningEffort };
};
export function ConfigurableComposer() {
const [model, setModel] = useState("gpt-5");
const [reasoningEffort, setReasoningEffort] = useState<ReasoningEffort>("medium");
const chat = useChat<ChatRequest>({
endpoint: "http://localhost:8787/api/chat",
createRequest: ({ coreMessages }) => ({
messages: coreMessages,
stream: true,
model,
reasoning: { effort: reasoningEffort },
}),
});
return (
<ChatProvider controller={chat}>
<Composer.Root
className="composer"
submitMessage={async ({ input, attachments, chat: chatController, clear }) => {
await chatController.sendMessage({
text: input,
attachments,
metadata: { model, reasoningEffort },
});
clear();
}}
>
<select
aria-label="Model"
disabled={chat.status === "streaming"}
value={model}
onChange={(event) => setModel(event.currentTarget.value)}
>
<option value="gpt-5">GPT-5</option>
<option value="gpt-5-mini">GPT-5 mini</option>
</select>
<select
aria-label="Reasoning effort"
disabled={chat.status === "streaming"}
value={reasoningEffort}
onChange={(event) => setReasoningEffort(event.currentTarget.value as ReasoningEffort)}
>
<option value="low">Low</option>
<option value="medium">Medium</option>
<option value="high">High</option>
</select>
<Composer.Attachments className="attachments" />
<Composer.AddAttachment accept="image/*,.pdf" multiple>
Attach
</Composer.AddAttachment>
<Composer.Input minRows={1} maxRows={6} placeholder="Message Anvia..." />
<Composer.Stop>Stop</Composer.Stop>
<Composer.Submit>Send</Composer.Submit>
</Composer.Root>
</ChatProvider>
);
}Request options
Use createRequest for request-level options. The example sends model and reasoning next to
the converted core messages, so the server route can read them from the request body alongside
messages.
For the full request-body contract and metadata tradeoffs, see Request shape.
Custom submit
Use Composer.Root’s submitMessage when the composer should send a custom message payload, such
as metadata that records the selected model or reasoning effort. A custom submit handler replaces
the default send behavior, so call clear() after the message is accepted.
