feat(cli): derive Claude CLI model defaults from provider registry dynamically (#1393)

Integrated into release/v3.6.9
This commit is contained in:
Benson K B 2026-04-18 19:19:34 +05:30 committed by GitHub
parent 01ae037205
commit 891189bbf3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 78 additions and 11 deletions

View file

@ -6,13 +6,15 @@
## Quick Start
```bash
npm install # Install deps (auto-generates .env from .env.example)
npm run dev # Dev server at http://localhost:20128
npm run build # Production build (Next.js 16 standalone)
npm run lint # ESLint (0 errors expected; warnings are pre-existing)
npm run typecheck:core # TypeScript check (should be clean)
npm run test:coverage # Unit tests + coverage gate (60% min)
npm run check # lint + test combined
npm install # Install deps (auto-generates .env from .env.example)
npm run dev # Dev server at http://localhost:20128
npm run build # Production build (Next.js 16 standalone)
npm run lint # ESLint (0 errors expected; warnings are pre-existing)
npm run typecheck:core # TypeScript check (should be clean)
npm run typecheck:noimplicit:core # Strict check (no implicit any)
npm run test:coverage # Unit tests + coverage gate (60% min)
npm run check # lint + test combined
npm run check:cycles # Detect circular dependencies
```
### Running a Single Test
@ -172,6 +174,8 @@ Client → /v1/chat/completions (Next.js route)
**PR rule**: If you change production code in `src/`, `open-sse/`, `electron/`, or `bin/`,
you must include or update tests in the same PR.
**Test layer preference**: unit first → integration (multi-module or DB state) → e2e (UI/workflow only). Encode bug reproductions as automated tests before or alongside the fix.
---
## Git Workflow

View file

@ -7,6 +7,7 @@ RUN apt-get update \
COPY package*.json ./
COPY scripts/postinstall.mjs ./scripts/postinstall.mjs
COPY scripts/postinstallSupport.mjs ./scripts/postinstallSupport.mjs
COPY scripts/native-binary-compat.mjs ./scripts/native-binary-compat.mjs
COPY scripts/postinstallSupport.mjs ./scripts/postinstallSupport.mjs
RUN if [ -f package-lock.json ]; then npm ci --no-audit --no-fund; else npm install --no-audit --no-fund; fi

View file

@ -2149,3 +2149,22 @@ export function getProviderCategory(provider: string): "oauth" | "apikey" {
if (!entry) return "apikey"; // Safe default for unknown providers
return entry.authType === "apikey" ? "apikey" : "oauth";
}
/**
* Derive the latest opus/sonnet/haiku model IDs from the `claude` registry entry.
* Picks the first model whose ID matches each family pattern registry order
* determines precedence, so newer models should be listed first.
*/
export function getClaudeCodeDefaultModels(): {
opus: string;
sonnet: string;
haiku: string;
} {
const models = REGISTRY.claude?.models ?? [];
const find = (pattern: RegExp) => models.find((m) => pattern.test(m.id))?.id ?? "";
return {
opus: find(/opus/i),
sonnet: find(/sonnet/i),
haiku: find(/haiku/i),
};
}

View file

@ -148,7 +148,7 @@ export default function ClaudeToolCard({
}
tool.defaultModels.forEach((model) => {
const targetModel = modelMappings[model.alias];
const targetModel = modelMappings[model.alias] || model.defaultValue || "";
if (targetModel && model.envKey) env[model.envKey] = targetModel;
});

View file

@ -1,4 +1,8 @@
// CLI Tools configuration
import { getClaudeCodeDefaultModels } from "@omniroute/open-sse/config/providerRegistry";
const _cc = getClaudeCodeDefaultModels();
export const CLI_TOOLS = {
claude: {
id: "claude",
@ -19,26 +23,42 @@ export const CLI_TOOLS = {
settingsFile: "~/.claude/settings.json",
defaultCommand: "claude",
defaultModels: [
{
id: "model",
name: "Default Model",
alias: "model",
envKey: "ANTHROPIC_MODEL",
defaultValue: _cc.sonnet ? `cc/${_cc.sonnet}` : "cc/claude-sonnet-4-5-20250929",
isTopLevel: true,
},
{
id: "smallFast",
name: "Small Fast Model",
alias: "smallFast",
envKey: "ANTHROPIC_SMALL_FAST_MODEL",
defaultValue: _cc.haiku ? `cc/${_cc.haiku}` : "cc/claude-haiku-4-5-20251001",
isTopLevel: true,
},
{
id: "opus",
name: "Claude Opus",
alias: "opus",
envKey: "ANTHROPIC_DEFAULT_OPUS_MODEL",
defaultValue: "cc/claude-opus-4-5-20251101",
defaultValue: _cc.opus ? `cc/${_cc.opus}` : "cc/claude-opus-4-5-20251101",
},
{
id: "sonnet",
name: "Claude Sonnet",
alias: "sonnet",
envKey: "ANTHROPIC_DEFAULT_SONNET_MODEL",
defaultValue: "cc/claude-sonnet-4-5-20250929",
defaultValue: _cc.sonnet ? `cc/${_cc.sonnet}` : "cc/claude-sonnet-4-5-20250929",
},
{
id: "haiku",
name: "Claude Haiku",
alias: "haiku",
envKey: "ANTHROPIC_DEFAULT_HAIKU_MODEL",
defaultValue: "cc/claude-haiku-4-5-20251001",
defaultValue: _cc.haiku ? `cc/${_cc.haiku}` : "cc/claude-haiku-4-5-20251001",
},
],
},

View file

@ -0,0 +1,23 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { getClaudeCodeDefaultModels } from "../../open-sse/config/providerRegistry.ts";
test("getClaudeCodeDefaultModels returns expected default models", () => {
const models = getClaudeCodeDefaultModels();
// They should be non-empty strings because providerRegistry is populated statically
assert.ok(typeof models.opus === "string");
assert.ok(typeof models.sonnet === "string");
assert.ok(typeof models.haiku === "string");
// Check that the returned IDs match the expected patterns
if (models.opus) {
assert.match(models.opus, /opus/i);
}
if (models.sonnet) {
assert.match(models.sonnet, /sonnet/i);
}
if (models.haiku) {
assert.match(models.haiku, /haiku/i);
}
});