From 51b746a7d73a2da4aab6df11662e8d6e611fc717 Mon Sep 17 00:00:00 2001 From: Hamza Merzic Date: Wed, 22 Jul 2026 16:18:15 +0000 Subject: [PATCH 1/3] Align background-agent picker with Settings --- __tests__/news-regressions.test.mjs | 19 +++++ mobius.json | 2 +- package.json | 2 +- theme.js | 15 +++- ui/ModelPicker.jsx | 49 ++++++++++-- ui/SettingsTab.jsx | 114 ++++++++++------------------ 6 files changed, 117 insertions(+), 84 deletions(-) diff --git a/__tests__/news-regressions.test.mjs b/__tests__/news-regressions.test.mjs index b3eefdb..953b11d 100644 --- a/__tests__/news-regressions.test.mjs +++ b/__tests__/news-regressions.test.mjs @@ -443,6 +443,25 @@ test('settings writes explicit Background-agent modes and preserves legacy overr assert.equal(manifest.storage_seeds['agent.json'].secondary_agent_mode, 'system') }) +test('background agent slots use the Settings-style picker with an inherited default row', () => { + const settings = readRepoFile(join('ui', 'SettingsTab.jsx')) + const picker = readRepoFile(join('ui', 'ModelPicker.jsx')) + assert.ok(settings.includes("useSettingsDefault={primaryAgentMode === 'system'}")) + assert.ok(settings.includes("useSettingsDefault={secondaryAgentMode === 'system'}")) + assert.ok(settings.includes('onChange={saveAgent}')) + assert.ok(settings.includes("onSettingsDefault={() => savePrimaryMode('system')}")) + assert.ok(settings.includes('onChange={saveFallbackAgent}')) + assert.ok(settings.includes('onSettingsDefault={() => toggleFallback(false)}')) + assert.ok(!settings.includes('aria-label="News primary agent mode"')) + assert.ok(!settings.includes('aria-label="News secondary agent mode"')) + assert.ok(picker.includes('Default from settings')) + assert.ok(picker.includes('onSettingsDefault')) + assert.ok(picker.includes('aria-label={triggerLabel}')) + assert.ok(picker.includes('aria-pressed={useSettingsDefault}')) + assert.ok(picker.includes('aria-pressed={selected}')) + assert.ok(picker.includes('`${title}: ${modelName}${effortLabel ? `, ${effortLabel} effort`')) +}) + test('fetch.sh resolves and retries a configured fallback agent', () => { const sh = readRepoFile('fetch.sh') assert.ok(sh.includes('from app.background_agents import resolve_background_agents')) diff --git a/mobius.json b/mobius.json index 745267a..a029c84 100644 --- a/mobius.json +++ b/mobius.json @@ -1,7 +1,7 @@ { "id": "news", "name": "News", - "version": "1.14.10", + "version": "1.14.11", "description": "A daily AI-curated news digest you can tune by topic, schedule, and editorial brief.", "offline_capable": true, "embeds_agent": true, diff --git a/package.json b/package.json index 421a96a..247d791 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@mobius-os/app-news", - "version": "1.14.10", + "version": "1.14.11", "private": true, "type": "module", "scripts": { diff --git a/theme.js b/theme.js index 4a2b9bd..7ae411a 100644 --- a/theme.js +++ b/theme.js @@ -586,7 +586,20 @@ export const CSS = ` background: color-mix(in srgb, var(--accent) 12%, var(--surface)); border: 1px solid color-mix(in srgb, var(--accent) 24%, var(--border)); } -.mobius-model-trigger__caret { color: var(--muted); font-size: 11px; flex-shrink: 0; } +.mobius-model-trigger__effort-visual { + position: relative; flex-shrink: 0; display: inline-flex; align-items: center; + justify-content: space-between; gap: 5px; min-width: 68px; padding: 7px 3px; +} +.mobius-model-trigger__effort-visual::before { + content: ''; position: absolute; left: 6px; right: 6px; top: 50%; height: 1px; + background: var(--border); transform: translateY(-50%); +} +.mobius-model-trigger__effort-dot { + position: relative; z-index: 1; width: 6px; height: 6px; border-radius: 50%; + border: 1px solid var(--border); background: var(--surface); +} +.mobius-model-trigger__effort-dot.is-filled { border-color: var(--accent); background: var(--accent); } +.mobius-model-trigger__effort-dot.is-active { transform: scale(1.35); box-shadow: 0 0 0 2px var(--accent-dim); } .mobius-model-sheet__backdrop { position: absolute; inset: 0; z-index: 1000; display: flex; align-items: flex-end; justify-content: center; box-sizing: border-box; diff --git a/ui/ModelPicker.jsx b/ui/ModelPicker.jsx index e063605..0b8fd87 100644 --- a/ui/ModelPicker.jsx +++ b/ui/ModelPicker.jsx @@ -29,8 +29,12 @@ export function ModelPicker({ title = 'Model', navKey = 'model-picker', allowProviderDefault = false, + useSettingsDefault = false, + onSettingsDefault, effortControl = null, effortLabel = '', + efforts = [], + effort = '', }) { const [open, setOpen] = useState(false) const sheetRef = useRef(null) @@ -39,7 +43,13 @@ export function ModelPicker({ const navRef = useRef(null) const activeGroup = groups?.find((group) => group.key === provider) const activeModel = activeGroup?.models?.find((item) => item.id === model) - const modelName = activeModel?.name || (model ? model : activeGroup ? `${activeGroup.label} default` : 'Choose model') + const modelName = useSettingsDefault + ? 'Default from settings' + : (activeModel?.name || (model ? model : activeGroup ? `${activeGroup.label} default` : 'Choose model')) + const effortIndex = Math.max(0, efforts.findIndex((item) => item.value === effort)) + const triggerLabel = useSettingsDefault + ? `${title}: Default from settings` + : `${title}: ${modelName}${effortLabel ? `, ${effortLabel} effort` : ''}` const closeSheet = useCallback(() => { const handle = navRef.current @@ -113,16 +123,31 @@ export function ModelPicker({ className="mobius-model-trigger" onClick={openSheet} aria-haspopup="dialog" + aria-label={triggerLabel} > {modelName} - {model || 'Provider default'} + {!useSettingsDefault && ( + {model || 'Provider default'} + )} - {effortLabel && {effortLabel}} - + {!useSettingsDefault && effortLabel && efforts.length > 0 && ( +