// Coding-model picker for the Settings page. A trimmed modelBar: no engine selector and // no cache/delete controls (these are ZeroGPU sidecars with no browser download). Drives // the shared codingModel.js store, so the Skill Forge uses whatever is chosen here. import { listCodingModels, getCodingModelId, setCodingModel, currentCodingModel, onCodingModelChange, } from '/web/codingModel.js' function el(tag, props = {}, kids = []) { const n = document.createElement(tag) for (const [k, v] of Object.entries(props)) { if (k === 'class') n.className = v else if (k.startsWith('on') && typeof v === 'function') n.addEventListener(k.slice(2), v) else if (v != null) n.setAttribute(k, v) } for (const kid of [].concat(kids)) if (kid != null) n.append(kid) return n } export function mountCodingModelBar(host, { onChange } = {}) { const sel = el('select', { class: 'model-select' }) const info = el('div', { class: 'model-info' }) host.append(el('div', { class: 'model-bar' }, [ el('label', { class: 'persona-label' }, 'Model'), sel, el('div', { class: 'model-row' }, [info]), ])) function render() { sel.replaceChildren(...listCodingModels().map((m) => el('option', { value: m.id }, `${m.label}${m.params ? ` · ${m.params}` : ''}`))) sel.value = getCodingModelId() const m = currentCodingModel() info.textContent = [m.params, m.backend, m.note].filter(Boolean).join(' · ') } sel.addEventListener('change', () => { setCodingModel(sel.value); render(); onChange && onChange(sel.value) }) onCodingModelChange(render) render() return { refresh: render } }