feat: add preferred STT languages and fix model settings layout

This commit is contained in:
2026-10-26 02:14:27 +03:00
parent 70977bad84
commit ce28d95bcf
13 changed files with 195 additions and 50 deletions
+39 -37
View File
@@ -666,49 +666,51 @@ export function AgentSection({
label={SLOT_META[slot].label}
hint={SLOT_META[slot].roster}
testid={`slot-row-${slot}`}
className="flex-wrap gap-y-2"
className="flex-wrap items-start gap-y-2 [&>span:first-child]:flex-[1_1_12rem]"
>
{/* The anchor for the outside-click contract is the
span holding BOTH triggers of the open menu. */}
span holding the tier's controls. */}
<span
ref={thisMenuOpen ? menuAnchorRef : undefined}
className="relative ml-auto flex max-w-full flex-wrap items-center justify-end gap-2"
className="relative flex w-68 max-w-full shrink-0 flex-col items-start gap-2"
>
<span data-testid={`slot-controls-${slot}`} className="grid w-full grid-cols-[minmax(0,1fr)_5rem_auto] items-center gap-2">
<MenuTrigger
value={modelId ? prettyModel(modelId) : ""}
emptyLabel="—"
ariaLabel={t("{v0} model", { v0: t(SLOT_META[slot].label) })}
testid={`slot-model-${slot}`}
open={thisMenuOpen === "model"}
onClick={() => setOpenMenu(thisMenuOpen === "model" ? null : { target: slot, kind: "model" })}
widthClass="w-full min-w-0"
disabled={savingModels}
/>
<MenuTrigger
// Legacy display (chunk 2 item 4): no stored level + a known
// model → the RESOLVED level (the ordering's first supported —
// what the engine build runs). Display-only until a pick writes.
value={thinking || (chosen ? defaultOrderLevel(levels) : "")}
emptyLabel="—"
ariaLabel={t("{v0} thinking", { v0: t(SLOT_META[slot].label) })}
testid={`slot-thinking-${slot}`}
open={thisMenuOpen === "thinking"}
onClick={() => setOpenMenu(thisMenuOpen === "thinking" ? null : { target: slot, kind: "thinking" })}
widthClass="w-20"
disabled={savingModels}
/>
<Hint label={t(provider === "chatgpt" ? "Fast mode uses more ChatGPT allowance." : "Fast mode is available only for ChatGPT models.")}>
<span className="inline-flex">
<button type="button" data-testid={`slot-fast-${slot}`} aria-label={t("{v0} fast mode", { v0: t(SLOT_META[slot].label) })}
aria-pressed={provider === "chatgpt" && override?.fastMode === true} disabled={provider !== "chatgpt" || !chosen || savingModels}
onClick={() => { setOpenMenu(null); void updateModels(composeSlotFast(models, slot, !override?.fastMode)); }}
className={cn("flex h-7 items-center gap-1 rounded-sm border border-border px-1.5 font-ui text-xs transition-colors disabled:cursor-not-allowed disabled:opacity-40",
provider === "chatgpt" && override?.fastMode ? "bg-muted text-foreground" : "bg-background text-muted-foreground hover:border-muted-foreground/50")}>
<ZapIcon className="size-3.5" aria-hidden /><span>{t("Fast")}</span>
</button>
</span>
</Hint>
</span>
{slot !== "strong" && <><ChatGPTBackgroundAccess provider={coord?.provider} /><NativeSubscriptionBackgroundAccess provider={coord?.provider} /></>}
<MenuTrigger
value={modelId ? prettyModel(modelId) : ""}
emptyLabel="—"
ariaLabel={t("{v0} model", { v0: t(SLOT_META[slot].label) })}
testid={`slot-model-${slot}`}
open={thisMenuOpen === "model"}
onClick={() => setOpenMenu(thisMenuOpen === "model" ? null : { target: slot, kind: "model" })}
widthClass="min-w-20"
disabled={savingModels}
/>
<MenuTrigger
// Legacy display (chunk 2 item 4): no stored level + a known
// model → the RESOLVED level (the ordering's first supported —
// what the engine build runs). Display-only until a pick writes.
value={thinking || (chosen ? defaultOrderLevel(levels) : "")}
emptyLabel="—"
ariaLabel={t("{v0} thinking", { v0: t(SLOT_META[slot].label) })}
testid={`slot-thinking-${slot}`}
open={thisMenuOpen === "thinking"}
onClick={() => setOpenMenu(thisMenuOpen === "thinking" ? null : { target: slot, kind: "thinking" })}
widthClass="w-20"
disabled={savingModels}
/>
<Hint label={t(provider === "chatgpt" ? "Fast mode uses more ChatGPT allowance." : "Fast mode is available only for ChatGPT models.")}>
<span className="inline-flex">
<button type="button" data-testid={`slot-fast-${slot}`} aria-label={t("{v0} fast mode", { v0: t(SLOT_META[slot].label) })}
aria-pressed={provider === "chatgpt" && override?.fastMode === true} disabled={provider !== "chatgpt" || !chosen || savingModels}
onClick={() => { setOpenMenu(null); void updateModels(composeSlotFast(models, slot, !override?.fastMode)); }}
className={cn("flex h-7 items-center gap-1 rounded-sm border border-border px-1.5 font-ui text-xs transition-colors disabled:cursor-not-allowed disabled:opacity-40",
provider === "chatgpt" && override?.fastMode ? "bg-muted text-foreground" : "bg-background text-muted-foreground hover:border-muted-foreground/50")}>
<ZapIcon className="size-3.5" aria-hidden /><span>{t("Fast")}</span>
</button>
</span>
</Hint>
{thisMenuOpen === "model" && (
<MenuShell
preferredSide="down"