/** * Model, mode, approvals and thinking-effort dropdowns for a composer's bottom row. * Modes and approvals use icons; levels are plain text. */ import { useRef, useState } from "react"; import clsx from "clsx"; import type { AgentConfigOption } from "@/bindings"; import { useTx } from "@/platform/i18n"; import { IconButton, Popup, Select, T } from "@/ui"; import type { SelectOption } from "@/ui/Select"; import { mainOptions, modeIcon } from "./composerModel"; import styles from "./Composer.module.css"; export function configPickerOptions(option: AgentConfigOption): SelectOption[] { if (option.category !== "model") { return option.values.map((v) => ({ value: v.value, label: v.name, detail: v.description ?? undefined })); } const groups = new Map(); for (const v of option.values) { const slash = v.value.indexOf("/"); const provider = slash >= 0 ? v.value.slice(0, slash) : ""; const path = slash >= 0 ? v.value.slice(slash + 1) : ""; const label = path ? path.slice(path.lastIndexOf("/") + 1) : v.name || v.value; const detail = path ? [path, v.description].filter(Boolean).join(" · ") : (v.description ?? undefined); const bucket = groups.get(provider) ?? []; bucket.push({ value: v.value, label, detail, keywords: provider }); groups.set(provider, bucket); } const plain = groups.get("") ?? []; groups.delete(""); return [ ...plain, ...[...groups].flatMap(([provider, items]) => [{ value: provider, label: provider, section: true }, ...items]), ]; } export function ConfigPickers({ config, values, onChange, }: { config: readonly AgentConfigOption[]; /** Chosen values that override `current`, by option id. */ values?: Record; onChange: (option: string, value: string) => void; }) { const tx = useTx(); const [open, setOpen] = useState(false); const anchor = useRef(null); const options = mainOptions(config); const secondary = options.filter((o) => o.category !== "model"); const approval = secondary.find((o) => o.category === "approval" || o.category === "mode"); const summary = secondary .map((o) => { const value = values?.[o.id] ?? o.current; return `${tx(o.name)}: ${o.values.find((v) => v.value === value)?.name ?? tx("Default")}`; }) .join(" · "); return ( <> {options.map((o) => ( ))} {secondary.length > 0 && (
setOpen((v) => !v)} /> setOpen(false)} aria-label={tx("Agent settings")} className={styles.settingsPopup} >
Agent settings
{secondary.map((o) => (
{tx(o.name)}
))}
)} ); } function ConfigPicker({ option, value, onChange, framed = false, }: { option: AgentConfigOption; value: string | null; onChange: (option: string, value: string) => void; framed?: boolean; }) { const tx = useTx(); return (