From a78a3b3c69873371c5a831e76ffa4443010f4833 Mon Sep 17 00:00:00 2001 From: Codeman maintainer Date: Wed, 2 Sep 2026 08:52:00 +0200 Subject: [PATCH] feat(models): offer Fable 5.1 in the model picker and task routing Claude Code 2.1.258's baked-in model catalog carries `claude-fable-5-1` ("Fable 5.1", June 2026 cutoff), but App Settings only offered Fable 5, so pinning it meant hand-editing a case's .claude/settings.local.json. Fable 5.1 is added exactly the way Fable 5 already is: a base option carrying `data-ctx="1"` plus its `[1m]` companion row. The card grid and the context switch are built from those options, so this needs no settings-ui.js logic change at all - the card appears with the "1M capable" badge, the switch stays live for it, and base + switch compose back into `claude-fable-5-1[1m]`. Both strings are accepted by the CLI's catalog (verified: neither warns `unrecognized_model`, unlike a made-up id). The four per-agent-type routing selects and Default-for-tasks get the plain `claude-fable-5-1` value, matching how Fable 5 appears there. Deliberately NOT claimed: that Fable 5.1's 1M window is what sets it apart. The catalog marks BOTH fable entries `native_1m` with a 1e6 window, so a picker that gave 5.1 an always-on window and left 5 switchable would be drawing a distinction the models do not have. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01BHZgohZC5TbetqgETDnAve --- src/web/public/index.html | 9 ++++++++- src/web/public/settings-ui.js | 2 +- test/app-settings-structure.test.ts | 20 +++++++++++++++++++- 3 files changed, 28 insertions(+), 3 deletions(-) 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 @@
@@ -2080,6 +2082,7 @@ @@ -2104,6 +2108,7 @@ + @@ -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