Skip to content

fix: probe correct 5th-gen model IDs so Opus 5 appears in the model list - #520

Merged
alari76 merged 3 commits into
mainfrom
fix/opus-5-model-discovery
Jul 27, 2026
Merged

fix: probe correct 5th-gen model IDs so Opus 5 appears in the model list#520
alari76 merged 3 commits into
mainfrom
fix/opus-5-model-discovery

Conversation

@alari76

@alari76 alari76 commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Problem

Opus 5 never showed up in codekin's model selector, even though the installed Claude Code CLI supports it.

Model discovery in server/anthropic-models.ts has two strategies. The Anthropic API path is inert here — codekin's process env has no ANTHROPIC_API_KEY / CLAUDE_CODE_API_KEY, so fetchViaApi() returns null immediately. That leaves CLI probing, which spawns claude -p --model <id> over a hardcoded candidate list.

That list guessed the 5th-generation IDs with a -0 suffix:

'claude-opus-5-0',    // does not exist
'claude-sonnet-5-0',  // does not exist

The 5th generation uses dateless, single-number IDs — the same convention as claude-fable-5, which the list already probed correctly. So every Opus 5 probe failed silently, discovery capped out at Opus 4.8, and the UI showed that as newest.

Verified against the CLI

probed ID result
claude-opus-5 ✅ resolves (modelUsage=claude-opus-5)
claude-sonnet-5 ✅ resolves (modelUsage=claude-sonnet-5)
claude-opus-5-0 ❌ "may not exist"
claude-sonnet-5-0
claude-opus-4-9
claude-haiku-5 ❌ (Haiku 4.5 still latest — kept as probe-ahead)

Changes

  • Fixed the candidate IDs: claude-opus-5, claude-sonnet-5, claude-haiku-5.
  • Dropped the confirmed-nonexistent claude-opus-4-9 / claude-sonnet-4-8; added claude-opus-6 / claude-sonnet-6 as the new probe-ahead entries.
  • Added a comment recording the dateless-ID convention so the -0 guess doesn't reappear.
  • Added Opus 5 + Sonnet 5 to both fallback lists (FALLBACK_MODELS, CLAUDE_MODELS), Opus 5 firstgetDefaultClaudeModel() returns entry [0], so new sessions now start on Opus 5 instead of Opus 4.8.

Testing

  • server/anthropic-models.test.ts: 12/12 pass (tests reference FALLBACK_MODELS symbolically and mock the probe set, so they're insensitive to list contents).
  • Built both server and frontend; deployed and restarted on the live host. GET /api/claude/models now returns Opus 5 first.

Follow-up (not in this PR)

The underlying fragility remains: a hardcoded guess list needs manual edits for every new model family. Setting ANTHROPIC_API_KEY in codekin's env would make the API strategy return the full catalog and retire the guessing entirely.

🤖 Generated with Claude Code

https://claude.ai/code/session_01QNbRcczwaByehnDvarQFFu

alari76 and others added 2 commits July 27, 2026 17:11
Model discovery CLI-probes a hardcoded candidate list, and the 5th-gen
entries were guessed as `claude-opus-5-0` / `claude-sonnet-5-0`. Those IDs
don't exist — the 5th generation uses dateless, single-number IDs
(`claude-opus-5`), the same convention as `claude-fable-5`, which the list
already probed correctly. Every Opus 5 probe failed silently, so the
discovered list capped out at Opus 4.8 and the UI never offered Opus 5.

Verified against the CLI: `claude-opus-5` and `claude-sonnet-5` resolve;
`claude-opus-5-0`, `claude-sonnet-5-0`, `claude-opus-4-9` and
`claude-sonnet-4-8` all error as nonexistent, so the dead guesses are
dropped and `claude-opus-6` / `claude-sonnet-6` become the probe-ahead
entries.

Also adds Opus 5 and Sonnet 5 to both fallback lists, Opus 5 first —
`getDefaultClaudeModel()` returns entry [0], so new sessions now start on
Opus 5 instead of Opus 4.8.

Note this path only runs because codekin has no ANTHROPIC_API_KEY in its
env; with a key the API strategy would return the full catalog and no
hardcoded list would be needed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QNbRcczwaByehnDvarQFFu
CI #1279's `Audit dependencies` step failed on the root workspace with two
newly-published advisories against versions the lockfile had pinned:

- brace-expansion <=5.0.7 (high) — GHSA-mh99-v99m-4gvg, unbounded expansion
  length causing an OOM crash. The lockfile sat at exactly 5.0.7; 5.0.8 is
  the patched release. This is the one that tripped `--audit-level=high`.
- @babel/core <=7.29.0 (low) — GHSA-4x5r-pxfx-6jf8, arbitrary file read via
  sourceMappingURL comment. Pulled in transitively by
  eslint-plugin-react-hooks (^7.24.4); 7.29.7 is the patched 7.x.

brace-expansion was already an override, so bumping the range to ^5.0.8 and
re-resolving was enough. @babel/core is transitive only, so it gets a new
override pinned to the 7.x line rather than 8.x, keeping it inside the
`^7.24.4` and `^7.0.0` ranges its dependents declare.

No source changes; lint, build and the full 2497-test suite pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@alari76

alari76 commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

CI #1279 fix — dependency audit, not the model-discovery change

The failure was unrelated to this PR's source change. The Audit dependencies step (npm audit --audit-level=high) tripped on the root workspace over two advisories published against versions the lockfile already had pinned:

Package Locked Advisory Severity Patched
brace-expansion 5.0.7 GHSA-mh99-v99m-4gvg — DoS via unbounded expansion length (OOM crash) high 5.0.8
@babel/core 7.29.0 GHSA-4x5r-pxfx-6jf8 — arbitrary file read via sourceMappingURL comment low 7.29.7

Only brace-expansion actually failed the gate (--audit-level=high); @babel/core is bundled in the same fix since it was already flagged in the same run.

Changes (93918db)

  • brace-expansion was already an override — bumped the range ^5.0.7^5.0.8 and re-resolved.
  • @babel/core is transitive only (via eslint-plugin-react-hooks, which asks for ^7.24.4) — added an override pinned to ^7.29.7 rather than latest, so it stays on the 7.x line and inside the ^7.24.4 / ^7.0.0 peer ranges its dependents declare. Jumping to 8.x would break those.

package.json + package-lock.json only, no source changes. Lint, build, and the full suite (100 files / 2497 tests) pass locally.

Unrelated note

Both jobs also emit an annotation that actions/checkout@v4 and actions/setup-node@v4 target the now-deprecated Node 20 runtime. That's a warning, not the failure, and isn't touched here — worth a separate PR bumping both to @v5.

The previous bump fixed the root tree, but CI audits both — `npm audit`
then `cd server && npm audit`. The server tree still failed on postcss
(high, GHSA-r28c-9q8g-f849), pulled in transitively via vite, so CI
stayed red.

Adds a `postcss: ^8.5.18` override alongside the existing `vite` one,
matching how brace-expansion/@babel/core are pinned at the root. Resolves
to 8.5.23. Both trees now report 0 vulnerabilities; lint, root build and
server build all pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QNbRcczwaByehnDvarQFFu
@alari76
alari76 merged commit 50f6a4b into main Jul 27, 2026
2 checks passed
@alari76
alari76 deleted the fix/opus-5-model-discovery branch July 27, 2026 14:20
@alari76

alari76 commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

CI #1280 fix — Audit dependencies (both Node 20 and 22)

Root cause. The step runs two audits: npm audit at the root, then cd server && npm audit. Only the second one failed. A newly-published high advisory, GHSA-r28c-9q8g-f849 (postcss <=8.5.17, path traversal in previous-source-map auto-loading via sourceMappingURL, leading to arbitrary .map file disclosure), hit the server workspace.

postcss is dev-only and purely transitive there: vitest -> vite -> postcss@^8.5.15. The server lockfile had it resolved at exactly 8.5.15, inside the vulnerable range. The root tree was already clear at 8.5.21, which is why CI #1279's bump left this one behind.

Fix. Added a postcss: ^8.5.18 override in server/package.json, alongside the existing vite one — matching how brace-expansion/@babel/core are pinned at the root, so the floor survives future lockfile re-resolution. Re-resolving lands postcss 8.5.23 (and its nanoid dep at 3.3.16). Both are dev-only, so nothing changes in the shipped artifacts.

Verification. Reproduced the exact failure on the pre-change lockfile and confirmed it clears afterwards. Both workspaces now report 0 vulnerabilities at --audit-level=high; lint 0 errors, build succeeds, full 2497-test suite passes. Run 30274435481 is green on both Node 20 and 22.

Gotcha worth recording. Sandboxes that export NODE_ENV=production make npm default to omit=dev, so a plain local npm audit reports found 0 vulnerabilities and silently hides dev-only findings like this one. Reproducing CI locally needs NODE_ENV=development npm audit.

Note: a parallel session pushed fd4cd9d with byte-identical content while I was verifying. I confirmed the trees matched exactly and dropped my duplicate commit rather than adding noise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant