fix(ui): wire allowEmpty for embedding provider select (#112)

The `allowEmpty` prop on `ProviderModelSelect` was defined but the
Select dropdown still auto-selected the first provider when the value
was empty, and there was no way to reset back to empty (auto-detect).

- Map empty provider to a sentinel so Radix Select can represent it
- Show an "(auto)" option in the dropdown when `allowEmpty` is set
- Pass `allowEmpty` from both embedding config callers
- Skip clearing the model on provider change in allowEmpty mode to
  avoid a stale-closure bug where the second setState overwrites the
  provider update

Co-authored-by: Luvu182 <208665161+Luvu182@users.noreply.github.com>
This commit is contained in:
Luan VuandLuvu182 authored and GitHub committed 2026-03-10 18:45:09 +07:00
1 parent 25fd9c9d6d
commit 2495ff253c
3 files changed
+13 -2

No files matched your search

@@ -97,7 +97,13 @@ export function ProviderModelSelect({
const handleProviderChange = (v: string) => {
onProviderChange(v);
onModelChange("");
// Only clear model when NOT in allowEmpty mode.
// In allowEmpty mode (embedding config), both callbacks update the same
// parent state object — calling onModelChange("") with a stale closure
// would overwrite the provider change we just made.
if (!allowEmpty) {
onModelChange("");
}
};
const handleVerify = async () => {
@@ -110,11 +116,14 @@ export function ProviderModelSelect({
<div className="grid gap-1.5">
<InfoLabel tip={providerTip ?? t("providerTip")}>{providerLabel ?? t("provider")}</InfoLabel>
{enabledProviders.length > 0 ? (
<Select value={provider} onValueChange={handleProviderChange}>
<Select value={provider || "__empty__"} onValueChange={(v) => handleProviderChange(v === "__empty__" ? "" : v)}>
<SelectTrigger>
<SelectValue placeholder={providerPlaceholder ?? t("selectProvider")} />
</SelectTrigger>
<SelectContent>
{allowEmpty && (
<SelectItem value="__empty__">{providerPlaceholder || "(auto)"}</SelectItem>
)}
{enabledProviders.map((p) => (
<SelectItem key={p.name} value={p.name}>
{p.display_name || p.name}
@@ -40,6 +40,7 @@ export function MemorySection({ enabled, value, onToggle, onChange }: MemorySect
modelTip="Embedding model name (e.g. text-embedding-3-small). Must be supported by the provider."
providerPlaceholder="(auto)"
modelPlaceholder="text-embedding-3-small"
allowEmpty
/>
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
<div className="space-y-2">
@@ -183,6 +183,7 @@ export function AiDefaultsSection({ data, onSave, saving }: Props) {
modelTip={t("agents.memory.embeddingModelTip")}
providerPlaceholder="(auto)"
modelPlaceholder="text-embedding-3-small"
allowEmpty
/>
<div className="grid grid-cols-2 gap-4">
<Field label={t("agents.memory.maxResults")} tip={t("agents.memory.maxResultsTip")} type="number" value={memory.max_results} onChange={(v) => updateNested("memory", { max_results: Number(v) })} placeholder="6" />