diff --git a/src/web/public/index.html b/src/web/public/index.html index 78eff9d3..95cf7149 100644 --- a/src/web/public/index.html +++ b/src/web/public/index.html @@ -2028,6 +2028,8 @@
@@ -2114,6 +2119,7 @@ + @@ -2124,6 +2130,7 @@ + diff --git a/src/web/public/settings-ui.js b/src/web/public/settings-ui.js index 67be48d8..16838851 100644 --- a/src/web/public/settings-ui.js +++ b/src/web/public/settings-ui.js @@ -922,7 +922,7 @@ Object.assign(CodemanApp.prototype, { desc.textContent = inert ? 'The selected model has no 1M variant.' : base - ? 'Available for Fable 5, Opus and Opus 4.6.' + ? 'Available for Fable 5.1, Fable 5, Opus and Opus 4.6.' : 'With no model pinned, this starts new sessions on Opus with a 1M window.'; } }, diff --git a/test/app-settings-structure.test.ts b/test/app-settings-structure.test.ts index 4013497e..cdbbe1aa 100644 --- a/test/app-settings-structure.test.ts +++ b/test/app-settings-structure.test.ts @@ -120,13 +120,31 @@ describe('App Settings modal structure', () => { const select = modal.match(/id="appSettingsClaudeModel"([\s\S]*?)<\/select>/)?.[1] ?? ''; // The cards render the base models; the [1m] rows exist so that base + the // context switch can compose back into a real claudeModel value. - for (const value of ['opus[1m]', 'claude-fable-5[1m]', 'claude-opus-4-6[1m]']) { + for (const value of ['opus[1m]', 'claude-fable-5[1m]', 'claude-fable-5-1[1m]', 'claude-opus-4-6[1m]']) { expect(select).toContain(`value="${value}"`); } expect(select).toContain('data-ctx="1"'); expect(modal).toContain('id="appSettingsOpusContext1m"'); }); + it('models: offers Fable 5.1 as a card and to task routing', () => { + const modal = settingsModal(); + const select = modal.match(/id="appSettingsClaudeModel"([\s\S]*?)<\/select>/)?.[1] ?? ''; + // The cards are built from these options, so data-ctx is what keeps the 1M + // switch live for the model rather than greying the row out. + expect(select).toMatch(/value="claude-fable-5-1"[^>]*data-ctx="1"/); + for (const id of [ + 'appSettingsDefaultModel', + 'appSettingsModelExplore', + 'appSettingsModelImplement', + 'appSettingsModelTest', + 'appSettingsModelReview', + ]) { + const routing = modal.match(new RegExp(`id="${id}"([\\s\\S]*?)`))?.[1] ?? ''; + expect(routing, `${id} does not offer Fable 5.1`).toContain('value="claude-fable-5-1"'); + } + }); + it('has retired the modal-tab chrome everywhere, not just here', () => { // Session Options and Add Case moved onto this same `set-*` surface, so the // old tab classes have no users left. A reappearance means a modal drifted