roadmodel 0.2.61__tar.gz → 0.2.63__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {roadmodel-0.2.61 → roadmodel-0.2.63}/PKG-INFO +1 -1
- {roadmodel-0.2.61 → roadmodel-0.2.63}/docs/catalog.json +149 -7
- {roadmodel-0.2.61 → roadmodel-0.2.63}/pyproject.toml +1 -1
- {roadmodel-0.2.61 → roadmodel-0.2.63}/roadmodel/data/catalog.json +149 -7
- {roadmodel-0.2.61 → roadmodel-0.2.63}/src/roadmodel/__init__.py +1 -1
- {roadmodel-0.2.61 → roadmodel-0.2.63}/src/roadmodel/recommend.py +87 -26
- {roadmodel-0.2.61 → roadmodel-0.2.63}/src/roadmodel/scoring.py +212 -17
- {roadmodel-0.2.61 → roadmodel-0.2.63}/.gitignore +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/LICENSE +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/NOTICE +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/README.md +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/docs/benchmarks.json +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/docs/model-selector.txt +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/docs/model-tier-cost-scale.md +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/docs/settings-display.md +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/docs/templates/phase-roadmap-template.md +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/docs/templates/planning-kit-how-to-use.md +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/docs/templates/project-roadmap-template.md +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/docs/templates/prompt-phase-roadmap.md +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/docs/templates/prompt-project-roadmap.md +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/docs/user-context.example.md +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/hatch_build.py +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/infra/README.md +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/infra/gcp-killswitch/README.md +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/infra/supabase/README.md +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/roadmodel/data/benchmarks.json +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/roadmodel/data/model-selector.txt +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/roadmodel/data/model-tier-cost-scale.md +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/roadmodel/data/phase-roadmap-template.md +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/roadmodel/data/planning-kit-how-to-use.md +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/roadmodel/data/project-roadmap-template.md +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/roadmodel/data/prompt-phase-roadmap.md +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/roadmodel/data/prompt-project-roadmap.md +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/roadmodel/data/settings-display.md +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/roadmodel/data/user-context.example.md +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/scripts/update_projects.py +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/src/roadmodel/__main__.py +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/src/roadmodel/cli.py +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/src/roadmodel/config.py +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/src/roadmodel/cost.py +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/src/roadmodel/errors.py +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/src/roadmodel/mcp_server.py +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/src/roadmodel/providers/__init__.py +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/src/roadmodel/providers/anthropic.py +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/src/roadmodel/providers/google.py +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/src/roadmodel/providers/openai.py +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/src/roadmodel/providers/openai_compatible.py +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/src/roadmodel/providers/registry.py +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/src/roadmodel/usage.py +0 -0
- {roadmodel-0.2.61 → roadmodel-0.2.63}/src/roadmodel/user_context.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: roadmodel
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.63
|
|
4
4
|
Summary: BYO-key CLI that recommends the right AI model, platform, and settings for a prompt.
|
|
5
5
|
Project-URL: Homepage, https://roadmodel.ai
|
|
6
6
|
Project-URL: Repository, https://github.com/nathanramoscfa/roadmodel
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"schema_version": "
|
|
2
|
+
"schema_version": "4",
|
|
3
3
|
"output_contract_version": 2,
|
|
4
|
-
"generated_at_utc": "2026-10-
|
|
4
|
+
"generated_at_utc": "2026-10-02T18:08:21Z",
|
|
5
5
|
"source_doc_sha256": {
|
|
6
6
|
"model-selector.txt": "81c5530a28521df18ebe14810e56cd72e65f1e30ad93d0522d31dbf362516e93",
|
|
7
7
|
"model-tier-cost-scale.md": "2b3b0eb82237eb5cb5bf468a3fe971bcaf0160ad7d0bc700698d2c16640bc41d"
|
|
@@ -1523,7 +1523,78 @@
|
|
|
1523
1523
|
"exposes_max_mode": "no",
|
|
1524
1524
|
"exposes_thinking": "yes",
|
|
1525
1525
|
"exposes_orchestration": "yes",
|
|
1526
|
-
"best_for": "Default for Claude coding or terminal tasks when a claude.ai Max subscription is active \u2014 $0 marginal cost until the Max budget is exhausted, full tool-use surface, runs as a CLI, IDE extension inside Cursor, native VS Code extension, and as of 2.1.170+ also ships Claude Fable 5 (Mythos-class) plus a first-class Claude in Chrome browser-control integration (GA in 2.1.198), with Claude Sonnet 5 now the default model (2.1.197+) at native 1M-token context; as of 2.1.219 Claude Opus 5 ships as the new default Opus (1M context, fast mode at $10/$50 per Mtok) and Opus 4.7 is removed from fast mode so `/fast` now applies to Opus 5 and Opus 4.8; 2.1.280 ships Claude Opus 5.5 as the new default Opus (1M context, $4/$20 per Mtok with $0.20/Mtok cache reads) and changes the Pro and Team Standard default model from Sonnet to Opus (matching Max / Team Premium / Enterprise); 2.1.220\u20132.1.280 are bug-fix / reliability / self-hosted-runner / UI-polish / plugin-safety / VS Code / Claude apps / AGENTS.md / auto-mode-server-classifier releases with no effort/thinking surface changes beyond the 2.1.267 `maxEffortLevel` cap and the 2.1.269 `CLAUDE_CODE_WORKFLOW_MAX_CONCURRENT_AGENTS` (1\u2013256) knob for the Workflow tool's per-run concurrent-agent limit noted below (2.1.224 adds `claude self-hosted-runner` for turning your own machines into places where Claude Code web/mobile/desktop sessions can run, cross-session `SendMessage`, and archive-plugin sources; 2.1.225 adds gateway spend-limit reporting to the usage warning; 2.1.227 polishes the slash-command menu and fixes feature-flag evaluation for expired login tokens; 2.1.257 ships Claude Fable 5.1 as the new default Fable at 1M context and $10/$50 per Mtok; 2.1.259 adds `managedMcpServers` policy and `--permission-prompts none` for unattended headless hosts; 2.1.260 adds an inline `/diff` panel and a headless text form of `/advisor`; 2.1.261 adds `/skill-doctor` and `bashOutputMaxChars` / `taskOutputMaxChars` settings; 2.1.263 is a reliability release; 2.1.265 adds a `--plugin-dir` folder-of-plugins mode and tightens plugin path containment; 2.1.266 restores gateway/proxy behavior when `CLAUDE_CODE_USE_GATEWAY` is set alongside an API key or `apiKeyHelper`; 2.1.267 adds a `maxEffortLevel` setting \u2014 top-level or per model under `modelSettings` \u2014 that CAPS the effort level on every provider including Bedrock, Vertex, and Foundry while still letting users pick any lower level, plus `--system-prompt-snapshot off` for iterating on prompt text and a fix for `effort:` frontmatter on custom commands, skills, and subagents being ignored on models whose default effort is still pinned; 2.1.269 adds `claude plugin eval` for scored plugin eval suites, `/output-style [name]` to list and switch output styles (including over Remote Control and in headless sessions), a Bash-tool file-edit diff (setting `bashEditDiffEnabled`), `OTEL_METRICS_INCLUDE_REPOSITORY` for tagging OpenTelemetry metrics and events with `vcs.*` attributes, `CLAUDE_CODE_GATEWAY_MODEL_DISCOVERY_TIMEOUT_MS` to extend the LLM gateway `/v1/models` discovery timeout, and `CLAUDE_CODE_WORKFLOW_MAX_CONCURRENT_AGENTS` (1\u2013256) to raise the Workflow tool's per-run concurrent-agent limit for inference-bound fan-outs \u2014 none of which change the `/effort` vocabulary; 2.1.270 fixes read-only git commands in Bash unexpectedly asking for permission after a session had been running for a while, a 2.1.269 regression, with no surface changes; 2.1.271 adds fast mode in Claude Code Remote (cloud and self-hosted runner) sessions where organization policy allows it, mouse support in the `/config` panel, per-command Bash / PowerShell / Monitor `allowed_domains` in auto mode with sandboxing, agent-frontmatter and `--agents` JSON `omitClaudeMd` to let custom / plugin subagents run without CLAUDE.md files (managed policy still loads), and `--accept-command <sha256>` for `claude plugin install` / `update`; 2.1.272 is a bug-fix / reliability release; 2.1.273 adds `x-claude-code-*` LLM-gateway request-hint headers behind `CLAUDE_CODE_GATEWAY_HINT_HEADERS=1`, forking a `--remote-control` / `/remote-control` session from the Claude app as a local background session, and MCP-server-disconnected notifications, plus fixes for permission handling, credential/auth error messages, prompt-cache retention across `/login` / `/upgrade` / `/extra-usage`, and gateway 401 messaging \u2014 no effort/thinking surface changes; 2.1.274 adds a critical-memory-usage warning with recovery steps, `CLAUDE_CODE_MCP_STARTUP_WAIT_MS` to bound how long the first non-interactive turn waits for connecting MCP servers, an `effort` attribute on the `claude_code.llm_request` OpenTelemetry trace span, plus assorted VS Code, Claude Code on the web, Claude Tag, and Code Review fixes and improvements \u2014 no changes to the `/effort` vocabulary or extended-thinking controls; 2.1.275 adds signed-in account confirmation for Claude apps gateway sign-in, a send-now key (ctrl+enter, or ctrl+x ctrl+s) that flushes queued messages mid-turn, syncing of claude.ai-account skills and plugins into terminal sessions (opt out with `syncClaudeAiSkills: false` / `syncClaudeAiPlugins: false`), `/plugin install <plugin> --marketplace <source>`, and a startup warning when `otelHeadersHelper` fails, plus a broad set of reliability and rendering fixes \u2014 no changes to the `/effort` vocabulary or extended-thinking controls; 2.1.276 is a hotfix for a 2.1.275 regression where every request behind a proxy or gateway failed with `400 \u2026 Input tag 'advisor_20260301'`, with no surface changes; 2.1.277 adds AGENTS.md fallback support (in a project with no CLAUDE.md, Claude Code reads AGENTS.md instead \u2014 configurable under \"Project instructions\" in `/config`; extended by 2.1.281 to Bedrock, Vertex, Foundry, LLM gateways and telemetry-disabled sessions), `CLAUDE_GATEWAY_PROXY_IS_EGRESS_BOUNDARY=1` for Claude apps gateways whose only egress is a forward proxy, an optional `headers:` map on Claude apps gateway upstreams, plus assorted reliability, plugin, background-task, and VS Code / Claude Code on the web / Claude Tag fixes \u2014 no changes to the `/effort` vocabulary or extended-thinking controls; 2.1.278 changes auto mode for Claude API and Enterprise users, and on Bedrock, Vertex, Foundry and gateways, to default to the server-side classifier that does not charge for classifier overhead (opt out on Bedrock, Vertex, Foundry and gateways with `CLAUDE_CODE_AUTO_MODE_SERVER=0`; warns on billed fallback) and adds an `Auto mode server` row to `/status` showing whether this session's auto mode classifier runs on the server \u2014 no changes to the `/effort` vocabulary or extended-thinking controls; 2.1.280 ships Claude Opus 5.5 as the new default Opus model at 1M context and $4/$20 per Mtok, changes the Pro and Team Standard default model from Sonnet to Opus (matching Max / Team Premium / Enterprise), and stops Opus 4.7, Opus 4.8 and Fable 5 from holding their launch-default effort over an explicit `/effort`, `effortLevel`, project or managed setting \u2014 the `/effort` vocabulary itself is unchanged; 2.1.281\u20132.1.285 are reliability / plugin / gateway / VS Code / Claude Tag / Artifact releases, with 2.1.284 adding Claude Sonnet 5.5 as the default Sonnet on the Anthropic API (1M context, $2/$10 per Mtok) and making Ultracode its own `/effort` toggle, and 2.1.285 adding `claude --desktop` to open the Claude desktop app on the current directory and an `allowedProviders` managed setting). Exposes the full `/effort` dial (low/medium/high/xhigh/max \u2014 Opus 4.6 and Sonnet 4.6 top out at max with no xhigh step; Opus 5, Opus 5.5, Opus 4.7, Opus 4.8, Sonnet 5, Sonnet 5.5, Fable 5, and Fable 5.1 expose the full range; effort levels a model does not support fall back to the highest supported level at or below the requested one; deployments may set `maxEffortLevel` to cap the maximum reachable level on every provider), the Option+T/Alt+T, `alwaysThinkingEnabled`, and `MAX_THINKING_TOKENS=0` on/off controls, plus Ultracode (session-wide Dynamic Workflows tied to xhigh; since 2.1.284 its own `/effort` toggle \u2014 Tab or `/effort ultracode [on|off]` \u2014 that keeps the current effort level, with only `claude --effort ultracode` also setting xhigh; set via `/effort ultracode` or `\"ultracode\": true`; 2.1.202+ adds a `/config` \"Dynamic workflow size\" advisory guideline, 2.1.219 defaults it to medium (aim for fewer than 15 agents) with the `workflowSizeGuideline` settings key to set it from any settings file, and 2.1.269 adds `CLAUDE_CODE_WORKFLOW_MAX_CONCURRENT_AGENTS` (1\u2013256) to raise the per-run concurrent-agent cap for the Workflow tool) and the per-turn `ultrathink` keyword (`think`/`think hard`/`think more` are not recognized)."
|
|
1526
|
+
"best_for": "Default for Claude coding or terminal tasks when a claude.ai Max subscription is active \u2014 $0 marginal cost until the Max budget is exhausted, full tool-use surface, runs as a CLI, IDE extension inside Cursor, native VS Code extension, and as of 2.1.170+ also ships Claude Fable 5 (Mythos-class) plus a first-class Claude in Chrome browser-control integration (GA in 2.1.198), with Claude Sonnet 5 now the default model (2.1.197+) at native 1M-token context; as of 2.1.219 Claude Opus 5 ships as the new default Opus (1M context, fast mode at $10/$50 per Mtok) and Opus 4.7 is removed from fast mode so `/fast` now applies to Opus 5 and Opus 4.8; 2.1.280 ships Claude Opus 5.5 as the new default Opus (1M context, $4/$20 per Mtok with $0.20/Mtok cache reads) and changes the Pro and Team Standard default model from Sonnet to Opus (matching Max / Team Premium / Enterprise); 2.1.220\u20132.1.280 are bug-fix / reliability / self-hosted-runner / UI-polish / plugin-safety / VS Code / Claude apps / AGENTS.md / auto-mode-server-classifier releases with no effort/thinking surface changes beyond the 2.1.267 `maxEffortLevel` cap and the 2.1.269 `CLAUDE_CODE_WORKFLOW_MAX_CONCURRENT_AGENTS` (1\u2013256) knob for the Workflow tool's per-run concurrent-agent limit noted below (2.1.224 adds `claude self-hosted-runner` for turning your own machines into places where Claude Code web/mobile/desktop sessions can run, cross-session `SendMessage`, and archive-plugin sources; 2.1.225 adds gateway spend-limit reporting to the usage warning; 2.1.227 polishes the slash-command menu and fixes feature-flag evaluation for expired login tokens; 2.1.257 ships Claude Fable 5.1 as the new default Fable at 1M context and $10/$50 per Mtok; 2.1.259 adds `managedMcpServers` policy and `--permission-prompts none` for unattended headless hosts; 2.1.260 adds an inline `/diff` panel and a headless text form of `/advisor`; 2.1.261 adds `/skill-doctor` and `bashOutputMaxChars` / `taskOutputMaxChars` settings; 2.1.263 is a reliability release; 2.1.265 adds a `--plugin-dir` folder-of-plugins mode and tightens plugin path containment; 2.1.266 restores gateway/proxy behavior when `CLAUDE_CODE_USE_GATEWAY` is set alongside an API key or `apiKeyHelper`; 2.1.267 adds a `maxEffortLevel` setting \u2014 top-level or per model under `modelSettings` \u2014 that CAPS the effort level on every provider including Bedrock, Vertex, and Foundry while still letting users pick any lower level, plus `--system-prompt-snapshot off` for iterating on prompt text and a fix for `effort:` frontmatter on custom commands, skills, and subagents being ignored on models whose default effort is still pinned; 2.1.269 adds `claude plugin eval` for scored plugin eval suites, `/output-style [name]` to list and switch output styles (including over Remote Control and in headless sessions), a Bash-tool file-edit diff (setting `bashEditDiffEnabled`), `OTEL_METRICS_INCLUDE_REPOSITORY` for tagging OpenTelemetry metrics and events with `vcs.*` attributes, `CLAUDE_CODE_GATEWAY_MODEL_DISCOVERY_TIMEOUT_MS` to extend the LLM gateway `/v1/models` discovery timeout, and `CLAUDE_CODE_WORKFLOW_MAX_CONCURRENT_AGENTS` (1\u2013256) to raise the Workflow tool's per-run concurrent-agent limit for inference-bound fan-outs \u2014 none of which change the `/effort` vocabulary; 2.1.270 fixes read-only git commands in Bash unexpectedly asking for permission after a session had been running for a while, a 2.1.269 regression, with no surface changes; 2.1.271 adds fast mode in Claude Code Remote (cloud and self-hosted runner) sessions where organization policy allows it, mouse support in the `/config` panel, per-command Bash / PowerShell / Monitor `allowed_domains` in auto mode with sandboxing, agent-frontmatter and `--agents` JSON `omitClaudeMd` to let custom / plugin subagents run without CLAUDE.md files (managed policy still loads), and `--accept-command <sha256>` for `claude plugin install` / `update`; 2.1.272 is a bug-fix / reliability release; 2.1.273 adds `x-claude-code-*` LLM-gateway request-hint headers behind `CLAUDE_CODE_GATEWAY_HINT_HEADERS=1`, forking a `--remote-control` / `/remote-control` session from the Claude app as a local background session, and MCP-server-disconnected notifications, plus fixes for permission handling, credential/auth error messages, prompt-cache retention across `/login` / `/upgrade` / `/extra-usage`, and gateway 401 messaging \u2014 no effort/thinking surface changes; 2.1.274 adds a critical-memory-usage warning with recovery steps, `CLAUDE_CODE_MCP_STARTUP_WAIT_MS` to bound how long the first non-interactive turn waits for connecting MCP servers, an `effort` attribute on the `claude_code.llm_request` OpenTelemetry trace span, plus assorted VS Code, Claude Code on the web, Claude Tag, and Code Review fixes and improvements \u2014 no changes to the `/effort` vocabulary or extended-thinking controls; 2.1.275 adds signed-in account confirmation for Claude apps gateway sign-in, a send-now key (ctrl+enter, or ctrl+x ctrl+s) that flushes queued messages mid-turn, syncing of claude.ai-account skills and plugins into terminal sessions (opt out with `syncClaudeAiSkills: false` / `syncClaudeAiPlugins: false`), `/plugin install <plugin> --marketplace <source>`, and a startup warning when `otelHeadersHelper` fails, plus a broad set of reliability and rendering fixes \u2014 no changes to the `/effort` vocabulary or extended-thinking controls; 2.1.276 is a hotfix for a 2.1.275 regression where every request behind a proxy or gateway failed with `400 \u2026 Input tag 'advisor_20260301'`, with no surface changes; 2.1.277 adds AGENTS.md fallback support (in a project with no CLAUDE.md, Claude Code reads AGENTS.md instead \u2014 configurable under \"Project instructions\" in `/config`; extended by 2.1.281 to Bedrock, Vertex, Foundry, LLM gateways and telemetry-disabled sessions), `CLAUDE_GATEWAY_PROXY_IS_EGRESS_BOUNDARY=1` for Claude apps gateways whose only egress is a forward proxy, an optional `headers:` map on Claude apps gateway upstreams, plus assorted reliability, plugin, background-task, and VS Code / Claude Code on the web / Claude Tag fixes \u2014 no changes to the `/effort` vocabulary or extended-thinking controls; 2.1.278 changes auto mode for Claude API and Enterprise users, and on Bedrock, Vertex, Foundry and gateways, to default to the server-side classifier that does not charge for classifier overhead (opt out on Bedrock, Vertex, Foundry and gateways with `CLAUDE_CODE_AUTO_MODE_SERVER=0`; warns on billed fallback) and adds an `Auto mode server` row to `/status` showing whether this session's auto mode classifier runs on the server \u2014 no changes to the `/effort` vocabulary or extended-thinking controls; 2.1.280 ships Claude Opus 5.5 as the new default Opus model at 1M context and $4/$20 per Mtok, changes the Pro and Team Standard default model from Sonnet to Opus (matching Max / Team Premium / Enterprise), and stops Opus 4.7, Opus 4.8 and Fable 5 from holding their launch-default effort over an explicit `/effort`, `effortLevel`, project or managed setting \u2014 the `/effort` vocabulary itself is unchanged; 2.1.281\u20132.1.285 are reliability / plugin / gateway / VS Code / Claude Tag / Artifact releases, with 2.1.284 adding Claude Sonnet 5.5 as the default Sonnet on the Anthropic API (1M context, $2/$10 per Mtok) and making Ultracode its own `/effort` toggle, and 2.1.285 adding `claude --desktop` to open the Claude desktop app on the current directory and an `allowedProviders` managed setting). Exposes the full `/effort` dial (low/medium/high/xhigh/max \u2014 Opus 4.6 and Sonnet 4.6 top out at max with no xhigh step; Opus 5, Opus 5.5, Opus 4.7, Opus 4.8, Sonnet 5, Sonnet 5.5, Fable 5, and Fable 5.1 expose the full range; effort levels a model does not support fall back to the highest supported level at or below the requested one; deployments may set `maxEffortLevel` to cap the maximum reachable level on every provider), the Option+T/Alt+T, `alwaysThinkingEnabled`, and `MAX_THINKING_TOKENS=0` on/off controls, plus Ultracode (session-wide Dynamic Workflows tied to xhigh; since 2.1.284 its own `/effort` toggle \u2014 Tab or `/effort ultracode [on|off]` \u2014 that keeps the current effort level, with only `claude --effort ultracode` also setting xhigh; set via `/effort ultracode` or `\"ultracode\": true`; 2.1.202+ adds a `/config` \"Dynamic workflow size\" advisory guideline, 2.1.219 defaults it to medium (aim for fewer than 15 agents) with the `workflowSizeGuideline` settings key to set it from any settings file, and 2.1.269 adds `CLAUDE_CODE_WORKFLOW_MAX_CONCURRENT_AGENTS` (1\u2013256) to raise the per-run concurrent-agent cap for the Workflow tool) and the per-turn `ultrathink` keyword (`think`/`think hard`/`think more` are not recognized).",
|
|
1527
|
+
"effort_levels": [
|
|
1528
|
+
"low",
|
|
1529
|
+
"medium",
|
|
1530
|
+
"high",
|
|
1531
|
+
"xhigh",
|
|
1532
|
+
"max"
|
|
1533
|
+
],
|
|
1534
|
+
"effort_levels_by_model": {
|
|
1535
|
+
"claude-fable-5": [
|
|
1536
|
+
"low",
|
|
1537
|
+
"medium",
|
|
1538
|
+
"high",
|
|
1539
|
+
"xhigh",
|
|
1540
|
+
"max"
|
|
1541
|
+
],
|
|
1542
|
+
"claude-fable-5.1": [
|
|
1543
|
+
"low",
|
|
1544
|
+
"medium",
|
|
1545
|
+
"high",
|
|
1546
|
+
"xhigh",
|
|
1547
|
+
"max"
|
|
1548
|
+
],
|
|
1549
|
+
"claude-opus-5": [
|
|
1550
|
+
"low",
|
|
1551
|
+
"medium",
|
|
1552
|
+
"high",
|
|
1553
|
+
"xhigh",
|
|
1554
|
+
"max"
|
|
1555
|
+
],
|
|
1556
|
+
"claude-opus-5-5": [
|
|
1557
|
+
"low",
|
|
1558
|
+
"medium",
|
|
1559
|
+
"high",
|
|
1560
|
+
"xhigh",
|
|
1561
|
+
"max"
|
|
1562
|
+
],
|
|
1563
|
+
"claude-sonnet-5": [
|
|
1564
|
+
"low",
|
|
1565
|
+
"medium",
|
|
1566
|
+
"high",
|
|
1567
|
+
"xhigh",
|
|
1568
|
+
"max"
|
|
1569
|
+
],
|
|
1570
|
+
"claude-sonnet-5-5": [
|
|
1571
|
+
"low",
|
|
1572
|
+
"medium",
|
|
1573
|
+
"high",
|
|
1574
|
+
"xhigh",
|
|
1575
|
+
"max"
|
|
1576
|
+
],
|
|
1577
|
+
"opus-4.7": [
|
|
1578
|
+
"low",
|
|
1579
|
+
"medium",
|
|
1580
|
+
"high",
|
|
1581
|
+
"xhigh",
|
|
1582
|
+
"max"
|
|
1583
|
+
],
|
|
1584
|
+
"opus-4.8": [
|
|
1585
|
+
"low",
|
|
1586
|
+
"medium",
|
|
1587
|
+
"high",
|
|
1588
|
+
"xhigh",
|
|
1589
|
+
"max"
|
|
1590
|
+
],
|
|
1591
|
+
"sonnet-4.6": [
|
|
1592
|
+
"low",
|
|
1593
|
+
"medium",
|
|
1594
|
+
"high",
|
|
1595
|
+
"max"
|
|
1596
|
+
]
|
|
1597
|
+
}
|
|
1527
1598
|
},
|
|
1528
1599
|
{
|
|
1529
1600
|
"id": "claude-web",
|
|
@@ -1578,7 +1649,15 @@
|
|
|
1578
1649
|
"exposes_max_mode": "no",
|
|
1579
1650
|
"exposes_thinking": "yes",
|
|
1580
1651
|
"exposes_orchestration": "no",
|
|
1581
|
-
"best_for": "The same Codex surface driven by an OpenAI API key instead of a ChatGPT sign-in: the ONLY way to run the coding-specialised `-codex` variants (gpt-5.3-codex and the gpt-5.1-codex family), and the fallback for GPT work once the ChatGPT plan's limits bind. Billed per token at list price, so prefer `codex-cli` while the subscription still has headroom. Exposes the full Codex `reasoning_effort` dial (`low`, `medium`, `high`, `xhigh`, `max`, `ultra`)."
|
|
1652
|
+
"best_for": "The same Codex surface driven by an OpenAI API key instead of a ChatGPT sign-in: the ONLY way to run the coding-specialised `-codex` variants (gpt-5.3-codex and the gpt-5.1-codex family), and the fallback for GPT work once the ChatGPT plan's limits bind. Billed per token at list price, so prefer `codex-cli` while the subscription still has headroom. Exposes the full Codex `reasoning_effort` dial (`low`, `medium`, `high`, `xhigh`, `max`, `ultra`).",
|
|
1653
|
+
"effort_levels": [
|
|
1654
|
+
"low",
|
|
1655
|
+
"medium",
|
|
1656
|
+
"high",
|
|
1657
|
+
"xhigh",
|
|
1658
|
+
"max",
|
|
1659
|
+
"ultra"
|
|
1660
|
+
]
|
|
1582
1661
|
},
|
|
1583
1662
|
{
|
|
1584
1663
|
"id": "codex-cli",
|
|
@@ -1605,7 +1684,15 @@
|
|
|
1605
1684
|
"exposes_max_mode": "no",
|
|
1606
1685
|
"exposes_thinking": "yes",
|
|
1607
1686
|
"exposes_orchestration": "no",
|
|
1608
|
-
"best_for": "Default for GPT-driven autonomous coding sessions when a ChatGPT Plus/Pro subscription is active \u2014 pays from the ChatGPT budget instead of the per-token API rate, in the CLI and the IDE extension. A ChatGPT-account sign-in CANNOT run the `-codex` model variants: Codex answers 400 "The 'gpt-5.3-codex' model is not supported when using Codex with a ChatGPT account." Those variants are reachable only through `codex-api` (an OpenAI API key), so recommending one here would name a model the operator's subscription cannot run. Exposes the full Codex `reasoning_effort` dial (`low`, `medium`, `high`, `xhigh`, `max`, `ultra` \u2014 the top `ultra` step is session-wide multi-agent orchestration on par with Claude Code's `ultracode`) and no Max Mode."
|
|
1687
|
+
"best_for": "Default for GPT-driven autonomous coding sessions when a ChatGPT Plus/Pro subscription is active \u2014 pays from the ChatGPT budget instead of the per-token API rate, in the CLI and the IDE extension. A ChatGPT-account sign-in CANNOT run the `-codex` model variants: Codex answers 400 "The 'gpt-5.3-codex' model is not supported when using Codex with a ChatGPT account." Those variants are reachable only through `codex-api` (an OpenAI API key), so recommending one here would name a model the operator's subscription cannot run. Exposes the full Codex `reasoning_effort` dial (`low`, `medium`, `high`, `xhigh`, `max`, `ultra` \u2014 the top `ultra` step is session-wide multi-agent orchestration on par with Claude Code's `ultracode`) and no Max Mode.",
|
|
1688
|
+
"effort_levels": [
|
|
1689
|
+
"low",
|
|
1690
|
+
"medium",
|
|
1691
|
+
"high",
|
|
1692
|
+
"xhigh",
|
|
1693
|
+
"max",
|
|
1694
|
+
"ultra"
|
|
1695
|
+
]
|
|
1609
1696
|
},
|
|
1610
1697
|
{
|
|
1611
1698
|
"id": "cursor",
|
|
@@ -1677,7 +1764,12 @@
|
|
|
1677
1764
|
"exposes_max_mode": "no",
|
|
1678
1765
|
"exposes_thinking": "yes",
|
|
1679
1766
|
"exposes_orchestration": "no",
|
|
1680
|
-
"best_for": "Direct DeepSeek API access (provider-direct per-token; OpenAI-format at api.deepseek.com and Anthropic-format at api.deepseek.com/anthropic) for the DeepSeek V4-series models (deepseek-flash = DeepSeek-V4.1-Flash, deepseek-v4-pro) \u2014 cost-conscious coding / reasoning / long-context (1M) work when the cn jurisdiction is acceptable and a deepseek-api-key is configured. Exposes the full thinking dial (toggle + reasoning_effort `low`/`high`/`max`). Not routed via the Cursor pool. cn-jurisdiction: excluded by the default allowed-jurisdictions list unless the user opts into cn."
|
|
1767
|
+
"best_for": "Direct DeepSeek API access (provider-direct per-token; OpenAI-format at api.deepseek.com and Anthropic-format at api.deepseek.com/anthropic) for the DeepSeek V4-series models (deepseek-flash = DeepSeek-V4.1-Flash, deepseek-v4-pro) \u2014 cost-conscious coding / reasoning / long-context (1M) work when the cn jurisdiction is acceptable and a deepseek-api-key is configured. Exposes the full thinking dial (toggle + reasoning_effort `low`/`high`/`max`). Not routed via the Cursor pool. cn-jurisdiction: excluded by the default allowed-jurisdictions list unless the user opts into cn.",
|
|
1768
|
+
"effort_levels": [
|
|
1769
|
+
"low",
|
|
1770
|
+
"high",
|
|
1771
|
+
"max"
|
|
1772
|
+
]
|
|
1681
1773
|
},
|
|
1682
1774
|
{
|
|
1683
1775
|
"id": "gemini-app",
|
|
@@ -1743,7 +1835,57 @@
|
|
|
1743
1835
|
"exposes_max_mode": "no",
|
|
1744
1836
|
"exposes_thinking": "yes",
|
|
1745
1837
|
"exposes_orchestration": "no",
|
|
1746
|
-
"best_for": "Programmatic / scripted Gemini use with a Google API key. Pay-per-token at Google's published rates. Exposes the discrete Gemini thinking-level dial (`minimal`, `low`, `medium`, `high`) shared across the 3.x and 2.5 generations \u2014 per-model support varies (Gemini 3 Pro is low/high only; Gemini 3.1 Pro / 3.7 Flash / 3.8 Flash / 2.5 Pro / 2.5 Flash / 2.5 Flash-Lite are low/medium/high without `minimal`; `minimal` appears on Flash-line models such as 3.6 Flash, 3.5 Flash, 3.5 Flash-Lite, 3.1 Flash-Lite Image, and 3 Flash). Powers the roadmodel SaaS free-tier surfaces (/recommend on Gemini 2.5 Flash; /roadmap on Gemini 2.5 Flash with 3.1 Pro escalation)."
|
|
1838
|
+
"best_for": "Programmatic / scripted Gemini use with a Google API key. Pay-per-token at Google's published rates. Exposes the discrete Gemini thinking-level dial (`minimal`, `low`, `medium`, `high`) shared across the 3.x and 2.5 generations \u2014 per-model support varies (Gemini 3 Pro is low/high only; Gemini 3.1 Pro / 3.7 Flash / 3.8 Flash / 2.5 Pro / 2.5 Flash / 2.5 Flash-Lite are low/medium/high without `minimal`; `minimal` appears on Flash-line models such as 3.6 Flash, 3.5 Flash, 3.5 Flash-Lite, 3.1 Flash-Lite Image, and 3 Flash). Powers the roadmodel SaaS free-tier surfaces (/recommend on Gemini 2.5 Flash; /roadmap on Gemini 2.5 Flash with 3.1 Pro escalation).",
|
|
1839
|
+
"effort_levels": [
|
|
1840
|
+
"minimal",
|
|
1841
|
+
"low",
|
|
1842
|
+
"medium",
|
|
1843
|
+
"high"
|
|
1844
|
+
],
|
|
1845
|
+
"effort_levels_by_model": {
|
|
1846
|
+
"gemini-2.5-flash": [
|
|
1847
|
+
"low",
|
|
1848
|
+
"medium",
|
|
1849
|
+
"high"
|
|
1850
|
+
],
|
|
1851
|
+
"gemini-3-flash": [
|
|
1852
|
+
"minimal",
|
|
1853
|
+
"low",
|
|
1854
|
+
"medium",
|
|
1855
|
+
"high"
|
|
1856
|
+
],
|
|
1857
|
+
"gemini-3-pro": [
|
|
1858
|
+
"low",
|
|
1859
|
+
"high"
|
|
1860
|
+
],
|
|
1861
|
+
"gemini-3.1-pro": [
|
|
1862
|
+
"low",
|
|
1863
|
+
"medium",
|
|
1864
|
+
"high"
|
|
1865
|
+
],
|
|
1866
|
+
"gemini-3.5-flash": [
|
|
1867
|
+
"minimal",
|
|
1868
|
+
"low",
|
|
1869
|
+
"medium",
|
|
1870
|
+
"high"
|
|
1871
|
+
],
|
|
1872
|
+
"gemini-3.6-flash": [
|
|
1873
|
+
"minimal",
|
|
1874
|
+
"low",
|
|
1875
|
+
"medium",
|
|
1876
|
+
"high"
|
|
1877
|
+
],
|
|
1878
|
+
"gemini-3.7-flash": [
|
|
1879
|
+
"low",
|
|
1880
|
+
"medium",
|
|
1881
|
+
"high"
|
|
1882
|
+
],
|
|
1883
|
+
"gemini-3.8-flash": [
|
|
1884
|
+
"low",
|
|
1885
|
+
"medium",
|
|
1886
|
+
"high"
|
|
1887
|
+
]
|
|
1888
|
+
}
|
|
1747
1889
|
},
|
|
1748
1890
|
{
|
|
1749
1891
|
"id": "groq-api",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"schema_version": "
|
|
2
|
+
"schema_version": "4",
|
|
3
3
|
"output_contract_version": 2,
|
|
4
|
-
"generated_at_utc": "2026-10-
|
|
4
|
+
"generated_at_utc": "2026-10-02T18:08:21Z",
|
|
5
5
|
"source_doc_sha256": {
|
|
6
6
|
"model-selector.txt": "81c5530a28521df18ebe14810e56cd72e65f1e30ad93d0522d31dbf362516e93",
|
|
7
7
|
"model-tier-cost-scale.md": "2b3b0eb82237eb5cb5bf468a3fe971bcaf0160ad7d0bc700698d2c16640bc41d"
|
|
@@ -1523,7 +1523,78 @@
|
|
|
1523
1523
|
"exposes_max_mode": "no",
|
|
1524
1524
|
"exposes_thinking": "yes",
|
|
1525
1525
|
"exposes_orchestration": "yes",
|
|
1526
|
-
"best_for": "Default for Claude coding or terminal tasks when a claude.ai Max subscription is active \u2014 $0 marginal cost until the Max budget is exhausted, full tool-use surface, runs as a CLI, IDE extension inside Cursor, native VS Code extension, and as of 2.1.170+ also ships Claude Fable 5 (Mythos-class) plus a first-class Claude in Chrome browser-control integration (GA in 2.1.198), with Claude Sonnet 5 now the default model (2.1.197+) at native 1M-token context; as of 2.1.219 Claude Opus 5 ships as the new default Opus (1M context, fast mode at $10/$50 per Mtok) and Opus 4.7 is removed from fast mode so `/fast` now applies to Opus 5 and Opus 4.8; 2.1.280 ships Claude Opus 5.5 as the new default Opus (1M context, $4/$20 per Mtok with $0.20/Mtok cache reads) and changes the Pro and Team Standard default model from Sonnet to Opus (matching Max / Team Premium / Enterprise); 2.1.220\u20132.1.280 are bug-fix / reliability / self-hosted-runner / UI-polish / plugin-safety / VS Code / Claude apps / AGENTS.md / auto-mode-server-classifier releases with no effort/thinking surface changes beyond the 2.1.267 `maxEffortLevel` cap and the 2.1.269 `CLAUDE_CODE_WORKFLOW_MAX_CONCURRENT_AGENTS` (1\u2013256) knob for the Workflow tool's per-run concurrent-agent limit noted below (2.1.224 adds `claude self-hosted-runner` for turning your own machines into places where Claude Code web/mobile/desktop sessions can run, cross-session `SendMessage`, and archive-plugin sources; 2.1.225 adds gateway spend-limit reporting to the usage warning; 2.1.227 polishes the slash-command menu and fixes feature-flag evaluation for expired login tokens; 2.1.257 ships Claude Fable 5.1 as the new default Fable at 1M context and $10/$50 per Mtok; 2.1.259 adds `managedMcpServers` policy and `--permission-prompts none` for unattended headless hosts; 2.1.260 adds an inline `/diff` panel and a headless text form of `/advisor`; 2.1.261 adds `/skill-doctor` and `bashOutputMaxChars` / `taskOutputMaxChars` settings; 2.1.263 is a reliability release; 2.1.265 adds a `--plugin-dir` folder-of-plugins mode and tightens plugin path containment; 2.1.266 restores gateway/proxy behavior when `CLAUDE_CODE_USE_GATEWAY` is set alongside an API key or `apiKeyHelper`; 2.1.267 adds a `maxEffortLevel` setting \u2014 top-level or per model under `modelSettings` \u2014 that CAPS the effort level on every provider including Bedrock, Vertex, and Foundry while still letting users pick any lower level, plus `--system-prompt-snapshot off` for iterating on prompt text and a fix for `effort:` frontmatter on custom commands, skills, and subagents being ignored on models whose default effort is still pinned; 2.1.269 adds `claude plugin eval` for scored plugin eval suites, `/output-style [name]` to list and switch output styles (including over Remote Control and in headless sessions), a Bash-tool file-edit diff (setting `bashEditDiffEnabled`), `OTEL_METRICS_INCLUDE_REPOSITORY` for tagging OpenTelemetry metrics and events with `vcs.*` attributes, `CLAUDE_CODE_GATEWAY_MODEL_DISCOVERY_TIMEOUT_MS` to extend the LLM gateway `/v1/models` discovery timeout, and `CLAUDE_CODE_WORKFLOW_MAX_CONCURRENT_AGENTS` (1\u2013256) to raise the Workflow tool's per-run concurrent-agent limit for inference-bound fan-outs \u2014 none of which change the `/effort` vocabulary; 2.1.270 fixes read-only git commands in Bash unexpectedly asking for permission after a session had been running for a while, a 2.1.269 regression, with no surface changes; 2.1.271 adds fast mode in Claude Code Remote (cloud and self-hosted runner) sessions where organization policy allows it, mouse support in the `/config` panel, per-command Bash / PowerShell / Monitor `allowed_domains` in auto mode with sandboxing, agent-frontmatter and `--agents` JSON `omitClaudeMd` to let custom / plugin subagents run without CLAUDE.md files (managed policy still loads), and `--accept-command <sha256>` for `claude plugin install` / `update`; 2.1.272 is a bug-fix / reliability release; 2.1.273 adds `x-claude-code-*` LLM-gateway request-hint headers behind `CLAUDE_CODE_GATEWAY_HINT_HEADERS=1`, forking a `--remote-control` / `/remote-control` session from the Claude app as a local background session, and MCP-server-disconnected notifications, plus fixes for permission handling, credential/auth error messages, prompt-cache retention across `/login` / `/upgrade` / `/extra-usage`, and gateway 401 messaging \u2014 no effort/thinking surface changes; 2.1.274 adds a critical-memory-usage warning with recovery steps, `CLAUDE_CODE_MCP_STARTUP_WAIT_MS` to bound how long the first non-interactive turn waits for connecting MCP servers, an `effort` attribute on the `claude_code.llm_request` OpenTelemetry trace span, plus assorted VS Code, Claude Code on the web, Claude Tag, and Code Review fixes and improvements \u2014 no changes to the `/effort` vocabulary or extended-thinking controls; 2.1.275 adds signed-in account confirmation for Claude apps gateway sign-in, a send-now key (ctrl+enter, or ctrl+x ctrl+s) that flushes queued messages mid-turn, syncing of claude.ai-account skills and plugins into terminal sessions (opt out with `syncClaudeAiSkills: false` / `syncClaudeAiPlugins: false`), `/plugin install <plugin> --marketplace <source>`, and a startup warning when `otelHeadersHelper` fails, plus a broad set of reliability and rendering fixes \u2014 no changes to the `/effort` vocabulary or extended-thinking controls; 2.1.276 is a hotfix for a 2.1.275 regression where every request behind a proxy or gateway failed with `400 \u2026 Input tag 'advisor_20260301'`, with no surface changes; 2.1.277 adds AGENTS.md fallback support (in a project with no CLAUDE.md, Claude Code reads AGENTS.md instead \u2014 configurable under \"Project instructions\" in `/config`; extended by 2.1.281 to Bedrock, Vertex, Foundry, LLM gateways and telemetry-disabled sessions), `CLAUDE_GATEWAY_PROXY_IS_EGRESS_BOUNDARY=1` for Claude apps gateways whose only egress is a forward proxy, an optional `headers:` map on Claude apps gateway upstreams, plus assorted reliability, plugin, background-task, and VS Code / Claude Code on the web / Claude Tag fixes \u2014 no changes to the `/effort` vocabulary or extended-thinking controls; 2.1.278 changes auto mode for Claude API and Enterprise users, and on Bedrock, Vertex, Foundry and gateways, to default to the server-side classifier that does not charge for classifier overhead (opt out on Bedrock, Vertex, Foundry and gateways with `CLAUDE_CODE_AUTO_MODE_SERVER=0`; warns on billed fallback) and adds an `Auto mode server` row to `/status` showing whether this session's auto mode classifier runs on the server \u2014 no changes to the `/effort` vocabulary or extended-thinking controls; 2.1.280 ships Claude Opus 5.5 as the new default Opus model at 1M context and $4/$20 per Mtok, changes the Pro and Team Standard default model from Sonnet to Opus (matching Max / Team Premium / Enterprise), and stops Opus 4.7, Opus 4.8 and Fable 5 from holding their launch-default effort over an explicit `/effort`, `effortLevel`, project or managed setting \u2014 the `/effort` vocabulary itself is unchanged; 2.1.281\u20132.1.285 are reliability / plugin / gateway / VS Code / Claude Tag / Artifact releases, with 2.1.284 adding Claude Sonnet 5.5 as the default Sonnet on the Anthropic API (1M context, $2/$10 per Mtok) and making Ultracode its own `/effort` toggle, and 2.1.285 adding `claude --desktop` to open the Claude desktop app on the current directory and an `allowedProviders` managed setting). Exposes the full `/effort` dial (low/medium/high/xhigh/max \u2014 Opus 4.6 and Sonnet 4.6 top out at max with no xhigh step; Opus 5, Opus 5.5, Opus 4.7, Opus 4.8, Sonnet 5, Sonnet 5.5, Fable 5, and Fable 5.1 expose the full range; effort levels a model does not support fall back to the highest supported level at or below the requested one; deployments may set `maxEffortLevel` to cap the maximum reachable level on every provider), the Option+T/Alt+T, `alwaysThinkingEnabled`, and `MAX_THINKING_TOKENS=0` on/off controls, plus Ultracode (session-wide Dynamic Workflows tied to xhigh; since 2.1.284 its own `/effort` toggle \u2014 Tab or `/effort ultracode [on|off]` \u2014 that keeps the current effort level, with only `claude --effort ultracode` also setting xhigh; set via `/effort ultracode` or `\"ultracode\": true`; 2.1.202+ adds a `/config` \"Dynamic workflow size\" advisory guideline, 2.1.219 defaults it to medium (aim for fewer than 15 agents) with the `workflowSizeGuideline` settings key to set it from any settings file, and 2.1.269 adds `CLAUDE_CODE_WORKFLOW_MAX_CONCURRENT_AGENTS` (1\u2013256) to raise the per-run concurrent-agent cap for the Workflow tool) and the per-turn `ultrathink` keyword (`think`/`think hard`/`think more` are not recognized)."
|
|
1526
|
+
"best_for": "Default for Claude coding or terminal tasks when a claude.ai Max subscription is active \u2014 $0 marginal cost until the Max budget is exhausted, full tool-use surface, runs as a CLI, IDE extension inside Cursor, native VS Code extension, and as of 2.1.170+ also ships Claude Fable 5 (Mythos-class) plus a first-class Claude in Chrome browser-control integration (GA in 2.1.198), with Claude Sonnet 5 now the default model (2.1.197+) at native 1M-token context; as of 2.1.219 Claude Opus 5 ships as the new default Opus (1M context, fast mode at $10/$50 per Mtok) and Opus 4.7 is removed from fast mode so `/fast` now applies to Opus 5 and Opus 4.8; 2.1.280 ships Claude Opus 5.5 as the new default Opus (1M context, $4/$20 per Mtok with $0.20/Mtok cache reads) and changes the Pro and Team Standard default model from Sonnet to Opus (matching Max / Team Premium / Enterprise); 2.1.220\u20132.1.280 are bug-fix / reliability / self-hosted-runner / UI-polish / plugin-safety / VS Code / Claude apps / AGENTS.md / auto-mode-server-classifier releases with no effort/thinking surface changes beyond the 2.1.267 `maxEffortLevel` cap and the 2.1.269 `CLAUDE_CODE_WORKFLOW_MAX_CONCURRENT_AGENTS` (1\u2013256) knob for the Workflow tool's per-run concurrent-agent limit noted below (2.1.224 adds `claude self-hosted-runner` for turning your own machines into places where Claude Code web/mobile/desktop sessions can run, cross-session `SendMessage`, and archive-plugin sources; 2.1.225 adds gateway spend-limit reporting to the usage warning; 2.1.227 polishes the slash-command menu and fixes feature-flag evaluation for expired login tokens; 2.1.257 ships Claude Fable 5.1 as the new default Fable at 1M context and $10/$50 per Mtok; 2.1.259 adds `managedMcpServers` policy and `--permission-prompts none` for unattended headless hosts; 2.1.260 adds an inline `/diff` panel and a headless text form of `/advisor`; 2.1.261 adds `/skill-doctor` and `bashOutputMaxChars` / `taskOutputMaxChars` settings; 2.1.263 is a reliability release; 2.1.265 adds a `--plugin-dir` folder-of-plugins mode and tightens plugin path containment; 2.1.266 restores gateway/proxy behavior when `CLAUDE_CODE_USE_GATEWAY` is set alongside an API key or `apiKeyHelper`; 2.1.267 adds a `maxEffortLevel` setting \u2014 top-level or per model under `modelSettings` \u2014 that CAPS the effort level on every provider including Bedrock, Vertex, and Foundry while still letting users pick any lower level, plus `--system-prompt-snapshot off` for iterating on prompt text and a fix for `effort:` frontmatter on custom commands, skills, and subagents being ignored on models whose default effort is still pinned; 2.1.269 adds `claude plugin eval` for scored plugin eval suites, `/output-style [name]` to list and switch output styles (including over Remote Control and in headless sessions), a Bash-tool file-edit diff (setting `bashEditDiffEnabled`), `OTEL_METRICS_INCLUDE_REPOSITORY` for tagging OpenTelemetry metrics and events with `vcs.*` attributes, `CLAUDE_CODE_GATEWAY_MODEL_DISCOVERY_TIMEOUT_MS` to extend the LLM gateway `/v1/models` discovery timeout, and `CLAUDE_CODE_WORKFLOW_MAX_CONCURRENT_AGENTS` (1\u2013256) to raise the Workflow tool's per-run concurrent-agent limit for inference-bound fan-outs \u2014 none of which change the `/effort` vocabulary; 2.1.270 fixes read-only git commands in Bash unexpectedly asking for permission after a session had been running for a while, a 2.1.269 regression, with no surface changes; 2.1.271 adds fast mode in Claude Code Remote (cloud and self-hosted runner) sessions where organization policy allows it, mouse support in the `/config` panel, per-command Bash / PowerShell / Monitor `allowed_domains` in auto mode with sandboxing, agent-frontmatter and `--agents` JSON `omitClaudeMd` to let custom / plugin subagents run without CLAUDE.md files (managed policy still loads), and `--accept-command <sha256>` for `claude plugin install` / `update`; 2.1.272 is a bug-fix / reliability release; 2.1.273 adds `x-claude-code-*` LLM-gateway request-hint headers behind `CLAUDE_CODE_GATEWAY_HINT_HEADERS=1`, forking a `--remote-control` / `/remote-control` session from the Claude app as a local background session, and MCP-server-disconnected notifications, plus fixes for permission handling, credential/auth error messages, prompt-cache retention across `/login` / `/upgrade` / `/extra-usage`, and gateway 401 messaging \u2014 no effort/thinking surface changes; 2.1.274 adds a critical-memory-usage warning with recovery steps, `CLAUDE_CODE_MCP_STARTUP_WAIT_MS` to bound how long the first non-interactive turn waits for connecting MCP servers, an `effort` attribute on the `claude_code.llm_request` OpenTelemetry trace span, plus assorted VS Code, Claude Code on the web, Claude Tag, and Code Review fixes and improvements \u2014 no changes to the `/effort` vocabulary or extended-thinking controls; 2.1.275 adds signed-in account confirmation for Claude apps gateway sign-in, a send-now key (ctrl+enter, or ctrl+x ctrl+s) that flushes queued messages mid-turn, syncing of claude.ai-account skills and plugins into terminal sessions (opt out with `syncClaudeAiSkills: false` / `syncClaudeAiPlugins: false`), `/plugin install <plugin> --marketplace <source>`, and a startup warning when `otelHeadersHelper` fails, plus a broad set of reliability and rendering fixes \u2014 no changes to the `/effort` vocabulary or extended-thinking controls; 2.1.276 is a hotfix for a 2.1.275 regression where every request behind a proxy or gateway failed with `400 \u2026 Input tag 'advisor_20260301'`, with no surface changes; 2.1.277 adds AGENTS.md fallback support (in a project with no CLAUDE.md, Claude Code reads AGENTS.md instead \u2014 configurable under \"Project instructions\" in `/config`; extended by 2.1.281 to Bedrock, Vertex, Foundry, LLM gateways and telemetry-disabled sessions), `CLAUDE_GATEWAY_PROXY_IS_EGRESS_BOUNDARY=1` for Claude apps gateways whose only egress is a forward proxy, an optional `headers:` map on Claude apps gateway upstreams, plus assorted reliability, plugin, background-task, and VS Code / Claude Code on the web / Claude Tag fixes \u2014 no changes to the `/effort` vocabulary or extended-thinking controls; 2.1.278 changes auto mode for Claude API and Enterprise users, and on Bedrock, Vertex, Foundry and gateways, to default to the server-side classifier that does not charge for classifier overhead (opt out on Bedrock, Vertex, Foundry and gateways with `CLAUDE_CODE_AUTO_MODE_SERVER=0`; warns on billed fallback) and adds an `Auto mode server` row to `/status` showing whether this session's auto mode classifier runs on the server \u2014 no changes to the `/effort` vocabulary or extended-thinking controls; 2.1.280 ships Claude Opus 5.5 as the new default Opus model at 1M context and $4/$20 per Mtok, changes the Pro and Team Standard default model from Sonnet to Opus (matching Max / Team Premium / Enterprise), and stops Opus 4.7, Opus 4.8 and Fable 5 from holding their launch-default effort over an explicit `/effort`, `effortLevel`, project or managed setting \u2014 the `/effort` vocabulary itself is unchanged; 2.1.281\u20132.1.285 are reliability / plugin / gateway / VS Code / Claude Tag / Artifact releases, with 2.1.284 adding Claude Sonnet 5.5 as the default Sonnet on the Anthropic API (1M context, $2/$10 per Mtok) and making Ultracode its own `/effort` toggle, and 2.1.285 adding `claude --desktop` to open the Claude desktop app on the current directory and an `allowedProviders` managed setting). Exposes the full `/effort` dial (low/medium/high/xhigh/max \u2014 Opus 4.6 and Sonnet 4.6 top out at max with no xhigh step; Opus 5, Opus 5.5, Opus 4.7, Opus 4.8, Sonnet 5, Sonnet 5.5, Fable 5, and Fable 5.1 expose the full range; effort levels a model does not support fall back to the highest supported level at or below the requested one; deployments may set `maxEffortLevel` to cap the maximum reachable level on every provider), the Option+T/Alt+T, `alwaysThinkingEnabled`, and `MAX_THINKING_TOKENS=0` on/off controls, plus Ultracode (session-wide Dynamic Workflows tied to xhigh; since 2.1.284 its own `/effort` toggle \u2014 Tab or `/effort ultracode [on|off]` \u2014 that keeps the current effort level, with only `claude --effort ultracode` also setting xhigh; set via `/effort ultracode` or `\"ultracode\": true`; 2.1.202+ adds a `/config` \"Dynamic workflow size\" advisory guideline, 2.1.219 defaults it to medium (aim for fewer than 15 agents) with the `workflowSizeGuideline` settings key to set it from any settings file, and 2.1.269 adds `CLAUDE_CODE_WORKFLOW_MAX_CONCURRENT_AGENTS` (1\u2013256) to raise the per-run concurrent-agent cap for the Workflow tool) and the per-turn `ultrathink` keyword (`think`/`think hard`/`think more` are not recognized).",
|
|
1527
|
+
"effort_levels": [
|
|
1528
|
+
"low",
|
|
1529
|
+
"medium",
|
|
1530
|
+
"high",
|
|
1531
|
+
"xhigh",
|
|
1532
|
+
"max"
|
|
1533
|
+
],
|
|
1534
|
+
"effort_levels_by_model": {
|
|
1535
|
+
"claude-fable-5": [
|
|
1536
|
+
"low",
|
|
1537
|
+
"medium",
|
|
1538
|
+
"high",
|
|
1539
|
+
"xhigh",
|
|
1540
|
+
"max"
|
|
1541
|
+
],
|
|
1542
|
+
"claude-fable-5.1": [
|
|
1543
|
+
"low",
|
|
1544
|
+
"medium",
|
|
1545
|
+
"high",
|
|
1546
|
+
"xhigh",
|
|
1547
|
+
"max"
|
|
1548
|
+
],
|
|
1549
|
+
"claude-opus-5": [
|
|
1550
|
+
"low",
|
|
1551
|
+
"medium",
|
|
1552
|
+
"high",
|
|
1553
|
+
"xhigh",
|
|
1554
|
+
"max"
|
|
1555
|
+
],
|
|
1556
|
+
"claude-opus-5-5": [
|
|
1557
|
+
"low",
|
|
1558
|
+
"medium",
|
|
1559
|
+
"high",
|
|
1560
|
+
"xhigh",
|
|
1561
|
+
"max"
|
|
1562
|
+
],
|
|
1563
|
+
"claude-sonnet-5": [
|
|
1564
|
+
"low",
|
|
1565
|
+
"medium",
|
|
1566
|
+
"high",
|
|
1567
|
+
"xhigh",
|
|
1568
|
+
"max"
|
|
1569
|
+
],
|
|
1570
|
+
"claude-sonnet-5-5": [
|
|
1571
|
+
"low",
|
|
1572
|
+
"medium",
|
|
1573
|
+
"high",
|
|
1574
|
+
"xhigh",
|
|
1575
|
+
"max"
|
|
1576
|
+
],
|
|
1577
|
+
"opus-4.7": [
|
|
1578
|
+
"low",
|
|
1579
|
+
"medium",
|
|
1580
|
+
"high",
|
|
1581
|
+
"xhigh",
|
|
1582
|
+
"max"
|
|
1583
|
+
],
|
|
1584
|
+
"opus-4.8": [
|
|
1585
|
+
"low",
|
|
1586
|
+
"medium",
|
|
1587
|
+
"high",
|
|
1588
|
+
"xhigh",
|
|
1589
|
+
"max"
|
|
1590
|
+
],
|
|
1591
|
+
"sonnet-4.6": [
|
|
1592
|
+
"low",
|
|
1593
|
+
"medium",
|
|
1594
|
+
"high",
|
|
1595
|
+
"max"
|
|
1596
|
+
]
|
|
1597
|
+
}
|
|
1527
1598
|
},
|
|
1528
1599
|
{
|
|
1529
1600
|
"id": "claude-web",
|
|
@@ -1578,7 +1649,15 @@
|
|
|
1578
1649
|
"exposes_max_mode": "no",
|
|
1579
1650
|
"exposes_thinking": "yes",
|
|
1580
1651
|
"exposes_orchestration": "no",
|
|
1581
|
-
"best_for": "The same Codex surface driven by an OpenAI API key instead of a ChatGPT sign-in: the ONLY way to run the coding-specialised `-codex` variants (gpt-5.3-codex and the gpt-5.1-codex family), and the fallback for GPT work once the ChatGPT plan's limits bind. Billed per token at list price, so prefer `codex-cli` while the subscription still has headroom. Exposes the full Codex `reasoning_effort` dial (`low`, `medium`, `high`, `xhigh`, `max`, `ultra`)."
|
|
1652
|
+
"best_for": "The same Codex surface driven by an OpenAI API key instead of a ChatGPT sign-in: the ONLY way to run the coding-specialised `-codex` variants (gpt-5.3-codex and the gpt-5.1-codex family), and the fallback for GPT work once the ChatGPT plan's limits bind. Billed per token at list price, so prefer `codex-cli` while the subscription still has headroom. Exposes the full Codex `reasoning_effort` dial (`low`, `medium`, `high`, `xhigh`, `max`, `ultra`).",
|
|
1653
|
+
"effort_levels": [
|
|
1654
|
+
"low",
|
|
1655
|
+
"medium",
|
|
1656
|
+
"high",
|
|
1657
|
+
"xhigh",
|
|
1658
|
+
"max",
|
|
1659
|
+
"ultra"
|
|
1660
|
+
]
|
|
1582
1661
|
},
|
|
1583
1662
|
{
|
|
1584
1663
|
"id": "codex-cli",
|
|
@@ -1605,7 +1684,15 @@
|
|
|
1605
1684
|
"exposes_max_mode": "no",
|
|
1606
1685
|
"exposes_thinking": "yes",
|
|
1607
1686
|
"exposes_orchestration": "no",
|
|
1608
|
-
"best_for": "Default for GPT-driven autonomous coding sessions when a ChatGPT Plus/Pro subscription is active \u2014 pays from the ChatGPT budget instead of the per-token API rate, in the CLI and the IDE extension. A ChatGPT-account sign-in CANNOT run the `-codex` model variants: Codex answers 400 "The 'gpt-5.3-codex' model is not supported when using Codex with a ChatGPT account." Those variants are reachable only through `codex-api` (an OpenAI API key), so recommending one here would name a model the operator's subscription cannot run. Exposes the full Codex `reasoning_effort` dial (`low`, `medium`, `high`, `xhigh`, `max`, `ultra` \u2014 the top `ultra` step is session-wide multi-agent orchestration on par with Claude Code's `ultracode`) and no Max Mode."
|
|
1687
|
+
"best_for": "Default for GPT-driven autonomous coding sessions when a ChatGPT Plus/Pro subscription is active \u2014 pays from the ChatGPT budget instead of the per-token API rate, in the CLI and the IDE extension. A ChatGPT-account sign-in CANNOT run the `-codex` model variants: Codex answers 400 "The 'gpt-5.3-codex' model is not supported when using Codex with a ChatGPT account." Those variants are reachable only through `codex-api` (an OpenAI API key), so recommending one here would name a model the operator's subscription cannot run. Exposes the full Codex `reasoning_effort` dial (`low`, `medium`, `high`, `xhigh`, `max`, `ultra` \u2014 the top `ultra` step is session-wide multi-agent orchestration on par with Claude Code's `ultracode`) and no Max Mode.",
|
|
1688
|
+
"effort_levels": [
|
|
1689
|
+
"low",
|
|
1690
|
+
"medium",
|
|
1691
|
+
"high",
|
|
1692
|
+
"xhigh",
|
|
1693
|
+
"max",
|
|
1694
|
+
"ultra"
|
|
1695
|
+
]
|
|
1609
1696
|
},
|
|
1610
1697
|
{
|
|
1611
1698
|
"id": "cursor",
|
|
@@ -1677,7 +1764,12 @@
|
|
|
1677
1764
|
"exposes_max_mode": "no",
|
|
1678
1765
|
"exposes_thinking": "yes",
|
|
1679
1766
|
"exposes_orchestration": "no",
|
|
1680
|
-
"best_for": "Direct DeepSeek API access (provider-direct per-token; OpenAI-format at api.deepseek.com and Anthropic-format at api.deepseek.com/anthropic) for the DeepSeek V4-series models (deepseek-flash = DeepSeek-V4.1-Flash, deepseek-v4-pro) \u2014 cost-conscious coding / reasoning / long-context (1M) work when the cn jurisdiction is acceptable and a deepseek-api-key is configured. Exposes the full thinking dial (toggle + reasoning_effort `low`/`high`/`max`). Not routed via the Cursor pool. cn-jurisdiction: excluded by the default allowed-jurisdictions list unless the user opts into cn."
|
|
1767
|
+
"best_for": "Direct DeepSeek API access (provider-direct per-token; OpenAI-format at api.deepseek.com and Anthropic-format at api.deepseek.com/anthropic) for the DeepSeek V4-series models (deepseek-flash = DeepSeek-V4.1-Flash, deepseek-v4-pro) \u2014 cost-conscious coding / reasoning / long-context (1M) work when the cn jurisdiction is acceptable and a deepseek-api-key is configured. Exposes the full thinking dial (toggle + reasoning_effort `low`/`high`/`max`). Not routed via the Cursor pool. cn-jurisdiction: excluded by the default allowed-jurisdictions list unless the user opts into cn.",
|
|
1768
|
+
"effort_levels": [
|
|
1769
|
+
"low",
|
|
1770
|
+
"high",
|
|
1771
|
+
"max"
|
|
1772
|
+
]
|
|
1681
1773
|
},
|
|
1682
1774
|
{
|
|
1683
1775
|
"id": "gemini-app",
|
|
@@ -1743,7 +1835,57 @@
|
|
|
1743
1835
|
"exposes_max_mode": "no",
|
|
1744
1836
|
"exposes_thinking": "yes",
|
|
1745
1837
|
"exposes_orchestration": "no",
|
|
1746
|
-
"best_for": "Programmatic / scripted Gemini use with a Google API key. Pay-per-token at Google's published rates. Exposes the discrete Gemini thinking-level dial (`minimal`, `low`, `medium`, `high`) shared across the 3.x and 2.5 generations \u2014 per-model support varies (Gemini 3 Pro is low/high only; Gemini 3.1 Pro / 3.7 Flash / 3.8 Flash / 2.5 Pro / 2.5 Flash / 2.5 Flash-Lite are low/medium/high without `minimal`; `minimal` appears on Flash-line models such as 3.6 Flash, 3.5 Flash, 3.5 Flash-Lite, 3.1 Flash-Lite Image, and 3 Flash). Powers the roadmodel SaaS free-tier surfaces (/recommend on Gemini 2.5 Flash; /roadmap on Gemini 2.5 Flash with 3.1 Pro escalation)."
|
|
1838
|
+
"best_for": "Programmatic / scripted Gemini use with a Google API key. Pay-per-token at Google's published rates. Exposes the discrete Gemini thinking-level dial (`minimal`, `low`, `medium`, `high`) shared across the 3.x and 2.5 generations \u2014 per-model support varies (Gemini 3 Pro is low/high only; Gemini 3.1 Pro / 3.7 Flash / 3.8 Flash / 2.5 Pro / 2.5 Flash / 2.5 Flash-Lite are low/medium/high without `minimal`; `minimal` appears on Flash-line models such as 3.6 Flash, 3.5 Flash, 3.5 Flash-Lite, 3.1 Flash-Lite Image, and 3 Flash). Powers the roadmodel SaaS free-tier surfaces (/recommend on Gemini 2.5 Flash; /roadmap on Gemini 2.5 Flash with 3.1 Pro escalation).",
|
|
1839
|
+
"effort_levels": [
|
|
1840
|
+
"minimal",
|
|
1841
|
+
"low",
|
|
1842
|
+
"medium",
|
|
1843
|
+
"high"
|
|
1844
|
+
],
|
|
1845
|
+
"effort_levels_by_model": {
|
|
1846
|
+
"gemini-2.5-flash": [
|
|
1847
|
+
"low",
|
|
1848
|
+
"medium",
|
|
1849
|
+
"high"
|
|
1850
|
+
],
|
|
1851
|
+
"gemini-3-flash": [
|
|
1852
|
+
"minimal",
|
|
1853
|
+
"low",
|
|
1854
|
+
"medium",
|
|
1855
|
+
"high"
|
|
1856
|
+
],
|
|
1857
|
+
"gemini-3-pro": [
|
|
1858
|
+
"low",
|
|
1859
|
+
"high"
|
|
1860
|
+
],
|
|
1861
|
+
"gemini-3.1-pro": [
|
|
1862
|
+
"low",
|
|
1863
|
+
"medium",
|
|
1864
|
+
"high"
|
|
1865
|
+
],
|
|
1866
|
+
"gemini-3.5-flash": [
|
|
1867
|
+
"minimal",
|
|
1868
|
+
"low",
|
|
1869
|
+
"medium",
|
|
1870
|
+
"high"
|
|
1871
|
+
],
|
|
1872
|
+
"gemini-3.6-flash": [
|
|
1873
|
+
"minimal",
|
|
1874
|
+
"low",
|
|
1875
|
+
"medium",
|
|
1876
|
+
"high"
|
|
1877
|
+
],
|
|
1878
|
+
"gemini-3.7-flash": [
|
|
1879
|
+
"low",
|
|
1880
|
+
"medium",
|
|
1881
|
+
"high"
|
|
1882
|
+
],
|
|
1883
|
+
"gemini-3.8-flash": [
|
|
1884
|
+
"low",
|
|
1885
|
+
"medium",
|
|
1886
|
+
"high"
|
|
1887
|
+
]
|
|
1888
|
+
}
|
|
1747
1889
|
},
|
|
1748
1890
|
{
|
|
1749
1891
|
"id": "groq-api",
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
# src/roadmodel/__init__.py
|
|
2
|
-
__version__ = "0.2.
|
|
2
|
+
__version__ = "0.2.63"
|
|
@@ -501,8 +501,10 @@ _SAAS_LADDER_TABLE_HEADER: Final = (
|
|
|
501
501
|
"gives both the same settings because a lower effort saves this user nothing or "
|
|
502
502
|
"the dial has no lower level; say which in that block's RATIONALE, and never "
|
|
503
503
|
"invent another difference.\n"
|
|
504
|
-
"- BACKUP
|
|
505
|
-
"
|
|
504
|
+
"- Each block's BACKUP is the model the row names after `backup` in that tier's "
|
|
505
|
+
"cell, copied verbatim; code checks it against the row and replaces one that "
|
|
506
|
+
"differs. Where a cell names no backup, BACKUP obeys the Step 7 HARD "
|
|
507
|
+
"cross-provider rule and names a model this user can reach.\n"
|
|
506
508
|
"- Each RATIONALE is three labelled segments (TASK: / PICK: / EFFORT:), one crisp "
|
|
507
509
|
"sentence each. PICK says why the row's model fits its tier in the table's terms "
|
|
508
510
|
"(where it sits on the user's frontier, its AA Index); EFFORT says why the setting "
|
|
@@ -1230,16 +1232,25 @@ def _ladder_tier_guard(picks: dict[str, dict[str, Any]]) -> dict[str, Any]:
|
|
|
1230
1232
|
}
|
|
1231
1233
|
|
|
1232
1234
|
|
|
1233
|
-
#
|
|
1235
|
+
# Effort levels as the selector's output format writes them: the scorer's
|
|
1236
|
+
# five and the native words some dials add (scoring.LEVEL_ORDER).
|
|
1234
1237
|
_EFFORT_WORDS: Final = {
|
|
1238
|
+
"none": "None",
|
|
1239
|
+
"minimal": "Minimal",
|
|
1235
1240
|
"low": "Low",
|
|
1236
1241
|
"medium": "Medium",
|
|
1237
1242
|
"high": "High",
|
|
1238
1243
|
"xhigh": "XHigh",
|
|
1239
1244
|
"max": "Max",
|
|
1245
|
+
"ultra": "Ultra",
|
|
1240
1246
|
}
|
|
1241
1247
|
|
|
1242
1248
|
|
|
1249
|
+
def _effort_word(level: str) -> str:
|
|
1250
|
+
"""A rung's level (native or scorer) as the EFFORT line writes it."""
|
|
1251
|
+
return _EFFORT_WORDS.get(scoring.normalize_level(level), level)
|
|
1252
|
+
|
|
1253
|
+
|
|
1243
1254
|
def _model_key(ref: str) -> str:
|
|
1244
1255
|
"""A spelling-free key for a model reference: "Claude Opus 5.5",
|
|
1245
1256
|
"Opus 5.5" and "claude-opus-5-5" all key the same."""
|
|
@@ -1304,7 +1315,7 @@ def _enforce_table_row(ladder: dict[str, dict[str, str]], row: scoring.Ladder) -
|
|
|
1304
1315
|
continue
|
|
1305
1316
|
rewritten.append(tier)
|
|
1306
1317
|
c = rung.candidate
|
|
1307
|
-
effort =
|
|
1318
|
+
effort = _effort_word(rung.level)
|
|
1308
1319
|
sections = _split_rationale_sections(base.get("rationale", ""))
|
|
1309
1320
|
task = (
|
|
1310
1321
|
sections["task"]
|
|
@@ -1322,35 +1333,79 @@ def _enforce_table_row(ladder: dict[str, dict[str, str]], row: scoring.Ladder) -
|
|
|
1322
1333
|
return rewritten
|
|
1323
1334
|
|
|
1324
1335
|
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1336
|
+
def _enforce_table_backup(ladder: dict[str, dict[str, str]], row: scoring.Ladder) -> list[str]:
|
|
1337
|
+
"""Make every rung's BACKUP the row's: the best model from another maker
|
|
1338
|
+
the user can run at no higher list price (scoring._backup_for). A rung
|
|
1339
|
+
whose row names no backup (no other maker funded) keeps the engine's,
|
|
1340
|
+
under the Step 7 guard. Returns the tiers whose backup it set."""
|
|
1341
|
+
adjusted: list[str] = []
|
|
1342
|
+
for tier in _LADDER_TIERS:
|
|
1343
|
+
backup = row.rungs[tier].backup
|
|
1344
|
+
if backup is None:
|
|
1345
|
+
continue
|
|
1346
|
+
b = backup.candidate
|
|
1347
|
+
written = ladder[tier].get("backup", "")
|
|
1348
|
+
if written and (
|
|
1349
|
+
cost.model_id_of(written) == b.model_id
|
|
1350
|
+
or _model_key(written) in {_model_key(b.model_id), _model_key(b.model_name)}
|
|
1351
|
+
):
|
|
1352
|
+
continue
|
|
1353
|
+
ladder[tier]["backup"] = b.model_name
|
|
1354
|
+
adjusted.append(tier)
|
|
1355
|
+
return adjusted
|
|
1330
1356
|
|
|
1331
1357
|
|
|
1332
|
-
def
|
|
1333
|
-
|
|
1334
|
-
|
|
1358
|
+
def _attach_backup_plans(picks: dict[str, dict[str, Any]], row: scoring.Ladder) -> None:
|
|
1359
|
+
"""Give each pick whose BACKUP is the row's a ``backup_plan``: the
|
|
1360
|
+
platform and effort the row runs that backup at, so a caller can show the
|
|
1361
|
+
backup on the surface the scorer chose (the user's subscription surface
|
|
1362
|
+
where one reaches it) instead of guessing one. A backup the guard replaced
|
|
1363
|
+
gets none."""
|
|
1364
|
+
for tier in _LADDER_TIERS:
|
|
1365
|
+
backup = row.rungs[tier].backup
|
|
1366
|
+
if backup is None:
|
|
1367
|
+
continue
|
|
1368
|
+
b = backup.candidate
|
|
1369
|
+
if picks[tier].get("backup") != cost.canonical_model_name(b.model_name):
|
|
1370
|
+
continue
|
|
1371
|
+
picks[tier]["backup_plan"] = {
|
|
1372
|
+
"model": picks[tier]["backup"],
|
|
1373
|
+
"platform": b.platform_name,
|
|
1374
|
+
"effort": _effort_word(backup.level),
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
|
|
1378
|
+
# Claude Code's Ultracode is a session setting above its Max level: it stands
|
|
1379
|
+
# where the row says max.
|
|
1380
|
+
_ULTRACODE_PLATFORM: Final = "claude-code"
|
|
1335
1381
|
|
|
1336
1382
|
|
|
1337
1383
|
def _enforce_table_effort(ladder: dict[str, dict[str, str]], row: scoring.Ladder) -> list[str]:
|
|
1338
|
-
"""On
|
|
1339
|
-
|
|
1340
|
-
EFFORT segment to match
|
|
1341
|
-
|
|
1342
|
-
|
|
1384
|
+
"""On every surface whose dial the catalog documents (the rung carries a
|
|
1385
|
+
native level), make the rung's EFFORT the row's level in that dial's own
|
|
1386
|
+
words and rewrite its EFFORT segment to match; on Claude Code, Ultracode
|
|
1387
|
+
stands where the row says max. Two rungs on one model are told apart by
|
|
1388
|
+
effort alone, so an engine that copies the model but not the effort makes
|
|
1389
|
+
them identical. A surface with no documented dial keeps the engine's
|
|
1390
|
+
mapping. Returns the tiers whose effort it set."""
|
|
1343
1391
|
adjusted: list[str] = []
|
|
1344
1392
|
for tier in _LADDER_TIERS:
|
|
1345
1393
|
base = ladder[tier]
|
|
1346
1394
|
rung = row.rungs[tier]
|
|
1347
|
-
if rung.
|
|
1395
|
+
if rung.native is None:
|
|
1396
|
+
continue
|
|
1397
|
+
written = scoring.normalize_level(base.get("effort", ""))
|
|
1398
|
+
want = scoring.normalize_level(rung.native)
|
|
1399
|
+
if written == want:
|
|
1348
1400
|
continue
|
|
1349
|
-
|
|
1350
|
-
|
|
1401
|
+
if (
|
|
1402
|
+
rung.candidate.platform_id == _ULTRACODE_PLATFORM
|
|
1403
|
+
and want == "max"
|
|
1404
|
+
and written == "ultracode"
|
|
1405
|
+
):
|
|
1351
1406
|
continue
|
|
1352
1407
|
adjusted.append(tier)
|
|
1353
|
-
effort =
|
|
1408
|
+
effort = _effort_word(rung.native)
|
|
1354
1409
|
base["effort"] = effort
|
|
1355
1410
|
sections = _split_rationale_sections(base.get("rationale", ""))
|
|
1356
1411
|
if sections:
|
|
@@ -1398,11 +1453,14 @@ def recommend_structured_ladder(
|
|
|
1398
1453
|
The picks come from this user's own cost/quality frontier: the scorer's
|
|
1399
1454
|
ladder table (scoring.ladder_table) goes into the prompt, the engine
|
|
1400
1455
|
classifies the task and copies its row, and every rung is then made the
|
|
1401
|
-
row's (:func:`_enforce_table_row`), effort included
|
|
1402
|
-
dial
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1456
|
+
row's (:func:`_enforce_table_row`), effort included on every surface
|
|
1457
|
+
whose dial the catalog documents (:func:`_enforce_table_effort`), and
|
|
1458
|
+
BACKUP included where the row names one (:func:`_enforce_table_backup`;
|
|
1459
|
+
such a pick also carries a ``backup_plan`` with the backup's platform and
|
|
1460
|
+
effort). ``guard`` then reports ``mode: "frontier"``, the row, how it was
|
|
1461
|
+
found, the tiers rewritten, the tiers whose effort was set and the tiers
|
|
1462
|
+
whose backup was set, and is healthy: two rungs on one model are the
|
|
1463
|
+
table's answer, not a collapse.
|
|
1406
1464
|
Without a table, or a response the table cannot place, the engine's own
|
|
1407
1465
|
picks stand under the tier-distinctness guard as before.
|
|
1408
1466
|
|
|
@@ -1449,6 +1507,7 @@ def recommend_structured_ladder(
|
|
|
1449
1507
|
"found": found,
|
|
1450
1508
|
"rewritten": _enforce_table_row(ladder, row),
|
|
1451
1509
|
"effort_set": _enforce_table_effort(ladder, row),
|
|
1510
|
+
"backup_set": _enforce_table_backup(ladder, row),
|
|
1452
1511
|
"frontier": [p.candidate.model_name for p in row.frontier],
|
|
1453
1512
|
}
|
|
1454
1513
|
else:
|
|
@@ -1463,6 +1522,8 @@ def recommend_structured_ladder(
|
|
|
1463
1522
|
)
|
|
1464
1523
|
for tier in _LADDER_TIERS
|
|
1465
1524
|
}
|
|
1525
|
+
if frontier_guard is not None and frontier_guard["classification"] is not None:
|
|
1526
|
+
_attach_backup_plans(picks, table[frontier_guard["classification"]])
|
|
1466
1527
|
guard = _ladder_tier_guard(picks)
|
|
1467
1528
|
if frontier_guard is not None:
|
|
1468
1529
|
guard.update(frontier_guard)
|
|
@@ -56,7 +56,7 @@ from __future__ import annotations
|
|
|
56
56
|
import json
|
|
57
57
|
import math
|
|
58
58
|
import re
|
|
59
|
-
from dataclasses import asdict, dataclass, field
|
|
59
|
+
from dataclasses import asdict, dataclass, field, replace
|
|
60
60
|
from datetime import datetime, timedelta, timezone
|
|
61
61
|
from importlib import resources
|
|
62
62
|
from typing import Any, Final
|
|
@@ -79,6 +79,21 @@ CATEGORIES: Final[tuple[str, ...]] = (
|
|
|
79
79
|
COMPLEXITIES: Final[tuple[str, ...]] = ("low", "medium", "high")
|
|
80
80
|
BUDGETS: Final[tuple[str, ...]] = ("cheap", "balanced", "best")
|
|
81
81
|
EFFORT_LADDER: Final[tuple[str, ...]] = ("low", "medium", "high", "xhigh", "max")
|
|
82
|
+
# Level names across every documented effort dial, lowest first: the scorer's
|
|
83
|
+
# five plus the words some surfaces add below or above them (Gemini's
|
|
84
|
+
# `minimal`, Codex's `ultra`). Orders and compares native levels; each
|
|
85
|
+
# surface's own list comes from the catalog's `effort_levels`, which
|
|
86
|
+
# update/build_catalog.py reads from the trackers' snapshots of its docs.
|
|
87
|
+
LEVEL_ORDER: Final[tuple[str, ...]] = (
|
|
88
|
+
"none",
|
|
89
|
+
"minimal",
|
|
90
|
+
"low",
|
|
91
|
+
"medium",
|
|
92
|
+
"high",
|
|
93
|
+
"xhigh",
|
|
94
|
+
"max",
|
|
95
|
+
"ultra",
|
|
96
|
+
)
|
|
82
97
|
|
|
83
98
|
# The Artificial Analysis evidence figure per category. For the five derived
|
|
84
99
|
# categories it is the evidence update/derive_ratings.py letters from, and the
|
|
@@ -621,6 +636,71 @@ def effort_for(task: Task, headroom: str, scarcity: float) -> str:
|
|
|
621
636
|
return EFFORT_LADDER[rung]
|
|
622
637
|
|
|
623
638
|
|
|
639
|
+
def normalize_level(value: str) -> str:
|
|
640
|
+
"""An effort level name compared case- and spacing-free: "XHigh",
|
|
641
|
+
"x-high" and "Extra high" are all ``xhigh``."""
|
|
642
|
+
level = re.sub(r"[\s_-]+", "", value.strip().lower())
|
|
643
|
+
return {"extrahigh": "xhigh"}.get(level, level)
|
|
644
|
+
|
|
645
|
+
|
|
646
|
+
def native_levels(
|
|
647
|
+
platform: str, model: str, *, catalog: dict[str, Any] | None = None
|
|
648
|
+
) -> list[str] | None:
|
|
649
|
+
"""The levels ``platform``'s effort dial offers for ``model``, lowest
|
|
650
|
+
first, as the catalog records them from that surface's own docs: the
|
|
651
|
+
method's ``effort_levels_by_model`` entry where its docs distinguish
|
|
652
|
+
models (a model they leave out has no documented dial), else its
|
|
653
|
+
``effort_levels``. None when the catalog documents no dial; the engine
|
|
654
|
+
then maps the scorer's level to the surface itself."""
|
|
655
|
+
cat = catalog if catalog is not None else _cost._load_catalog()
|
|
656
|
+
for method in cat.get("access_methods", []):
|
|
657
|
+
if not isinstance(method, dict) or method.get("id") != platform:
|
|
658
|
+
continue
|
|
659
|
+
by_model = method.get("effort_levels_by_model")
|
|
660
|
+
levels = by_model.get(model) if isinstance(by_model, dict) else method.get("effort_levels")
|
|
661
|
+
if isinstance(levels, list) and levels and all(isinstance(x, str) for x in levels):
|
|
662
|
+
return list(levels)
|
|
663
|
+
return None
|
|
664
|
+
return None
|
|
665
|
+
|
|
666
|
+
|
|
667
|
+
def native_level(
|
|
668
|
+
platform: str, model: str, scorer_level: str, *, catalog: dict[str, Any] | None = None
|
|
669
|
+
) -> str | None:
|
|
670
|
+
"""The level to set on ``platform``'s dial for ``model`` when the scorer
|
|
671
|
+
says ``scorer_level``: the native level of that name, else the highest
|
|
672
|
+
native level below it, else the dial's lowest. None when the catalog
|
|
673
|
+
documents no dial for the pair."""
|
|
674
|
+
levels = native_levels(platform, model, catalog=catalog)
|
|
675
|
+
if not levels:
|
|
676
|
+
return None
|
|
677
|
+
want = normalize_level(scorer_level)
|
|
678
|
+
for level in levels:
|
|
679
|
+
if normalize_level(level) == want:
|
|
680
|
+
return level
|
|
681
|
+
order = {name: i for i, name in enumerate(LEVEL_ORDER)}
|
|
682
|
+
if want in order:
|
|
683
|
+
below = [lv for lv in levels if order.get(normalize_level(lv), len(order)) < order[want]]
|
|
684
|
+
if below:
|
|
685
|
+
return max(below, key=lambda lv: order[normalize_level(lv)])
|
|
686
|
+
return levels[0]
|
|
687
|
+
|
|
688
|
+
|
|
689
|
+
def _scorer_level(native: str) -> str:
|
|
690
|
+
"""The scorer level a native level stands for: the highest of
|
|
691
|
+
EFFORT_LADDER at or below it, floored at ``low`` (Gemini's ``minimal``)
|
|
692
|
+
and capped at ``max`` (Codex's ``ultra``)."""
|
|
693
|
+
level = normalize_level(native)
|
|
694
|
+
if level in EFFORT_LADDER:
|
|
695
|
+
return level
|
|
696
|
+
order = {name: i for i, name in enumerate(LEVEL_ORDER)}
|
|
697
|
+
rank = order.get(level)
|
|
698
|
+
if rank is None:
|
|
699
|
+
return EFFORT_LADDER[0]
|
|
700
|
+
at_or_below = [e for e in EFFORT_LADDER if order[e] <= rank]
|
|
701
|
+
return at_or_below[-1] if at_or_below else EFFORT_LADDER[0]
|
|
702
|
+
|
|
703
|
+
|
|
624
704
|
def _quality(
|
|
625
705
|
model: dict[str, Any],
|
|
626
706
|
task: Task,
|
|
@@ -944,16 +1024,46 @@ class FrontierPoint:
|
|
|
944
1024
|
price_usd: float
|
|
945
1025
|
|
|
946
1026
|
|
|
1027
|
+
@dataclass(frozen=True)
|
|
1028
|
+
class Backup:
|
|
1029
|
+
"""A rung's cross-maker substitute, read off the frontier of the other
|
|
1030
|
+
makers' models (see :func:`ladder`)."""
|
|
1031
|
+
|
|
1032
|
+
point: FrontierPoint
|
|
1033
|
+
effort: str
|
|
1034
|
+
native: str | None = None
|
|
1035
|
+
|
|
1036
|
+
@property
|
|
1037
|
+
def candidate(self) -> Candidate:
|
|
1038
|
+
return self.point.candidate
|
|
1039
|
+
|
|
1040
|
+
@property
|
|
1041
|
+
def level(self) -> str:
|
|
1042
|
+
return self.native or self.effort
|
|
1043
|
+
|
|
1044
|
+
|
|
947
1045
|
@dataclass(frozen=True)
|
|
948
1046
|
class Rung:
|
|
949
1047
|
tier: str
|
|
950
1048
|
point: FrontierPoint
|
|
1049
|
+
# The scorer's level (EFFORT_LADDER) this rung runs at.
|
|
951
1050
|
effort: str
|
|
1051
|
+
# The same level as the platform's own dial names it (native_level), or
|
|
1052
|
+
# None when the catalog documents no dial for the platform and model.
|
|
1053
|
+
native: str | None = None
|
|
1054
|
+
# The best cross-maker substitute at no higher list price; None when the
|
|
1055
|
+
# pool holds no other maker's model.
|
|
1056
|
+
backup: Backup | None = None
|
|
952
1057
|
|
|
953
1058
|
@property
|
|
954
1059
|
def candidate(self) -> Candidate:
|
|
955
1060
|
return self.point.candidate
|
|
956
1061
|
|
|
1062
|
+
@property
|
|
1063
|
+
def level(self) -> str:
|
|
1064
|
+
"""The level the operator sets: the native word, else the scorer's."""
|
|
1065
|
+
return self.native or self.effort
|
|
1066
|
+
|
|
957
1067
|
|
|
958
1068
|
@dataclass
|
|
959
1069
|
class Ladder:
|
|
@@ -963,6 +1073,8 @@ class Ladder:
|
|
|
963
1073
|
# complexity's requirement, cheapest first.
|
|
964
1074
|
adequate: list[FrontierPoint]
|
|
965
1075
|
rungs: dict[str, Rung]
|
|
1076
|
+
# Why a rung has no backup: the pool holds no other maker's model.
|
|
1077
|
+
backup_warning: str | None = None
|
|
966
1078
|
|
|
967
1079
|
def to_dict(self) -> dict[str, Any]:
|
|
968
1080
|
def point(p: FrontierPoint) -> dict[str, Any]:
|
|
@@ -982,7 +1094,24 @@ class Ladder:
|
|
|
982
1094
|
"task": asdict(self.task),
|
|
983
1095
|
"frontier": [point(p) for p in self.frontier],
|
|
984
1096
|
"adequate": [p.candidate.model_id for p in self.adequate],
|
|
985
|
-
"rungs": {
|
|
1097
|
+
"rungs": {
|
|
1098
|
+
t: {
|
|
1099
|
+
**point(r.point),
|
|
1100
|
+
"effort": r.effort,
|
|
1101
|
+
"native_effort": r.native,
|
|
1102
|
+
"backup": (
|
|
1103
|
+
{
|
|
1104
|
+
**point(r.backup.point),
|
|
1105
|
+
"effort": r.backup.effort,
|
|
1106
|
+
"native_effort": r.backup.native,
|
|
1107
|
+
}
|
|
1108
|
+
if r.backup is not None
|
|
1109
|
+
else None
|
|
1110
|
+
),
|
|
1111
|
+
}
|
|
1112
|
+
for t, r in self.rungs.items()
|
|
1113
|
+
},
|
|
1114
|
+
"backup_warning": self.backup_warning,
|
|
986
1115
|
}
|
|
987
1116
|
|
|
988
1117
|
|
|
@@ -1030,12 +1159,16 @@ def ladder(
|
|
|
1030
1159
|
at the balanced posture; with none between, the COST or QUALITY model at
|
|
1031
1160
|
the balanced posture's effort, whichever differs from both other rungs.
|
|
1032
1161
|
- Each rung runs at :func:`effort_for` its posture (cheap / balanced /
|
|
1033
|
-
best) on its platform
|
|
1162
|
+
best), set on its platform's own dial (:func:`native_level`) where the
|
|
1163
|
+
catalog documents one. A lower rung on the same model and platform as
|
|
1034
1164
|
the rung above runs at least one effort level below it
|
|
1035
1165
|
(:func:`_below`), so the three picks stay distinct; at the dial's lowest
|
|
1036
1166
|
level they may converge. On an `uncapped` pool every free rung runs at
|
|
1037
1167
|
the top effort and two rungs on one model converge: a lower effort saves
|
|
1038
1168
|
that operator nothing.
|
|
1169
|
+
- Each rung carries a BACKUP from another maker (:func:`_backup_for`):
|
|
1170
|
+
the best adequate point on the other makers' frontier at no higher list
|
|
1171
|
+
price. ``backup_warning`` says why a rung has none.
|
|
1039
1172
|
|
|
1040
1173
|
None when no pool model carries an AA Index (no frontier to read)."""
|
|
1041
1174
|
cat = catalog if catalog is not None else _cost._load_catalog()
|
|
@@ -1065,10 +1198,12 @@ def ladder(
|
|
|
1065
1198
|
|
|
1066
1199
|
def rung(tier: str, p: FrontierPoint) -> Rung:
|
|
1067
1200
|
t = Task(task.category, task.complexity, task.novel, TIER_BUDGET[tier])
|
|
1068
|
-
|
|
1201
|
+
effort = effort_for(t, headroom, p.candidate.scarcity)
|
|
1202
|
+
c = p.candidate
|
|
1203
|
+
return Rung(tier, p, effort, native_level(c.platform_id, c.model_id, effort, catalog=cat))
|
|
1069
1204
|
|
|
1070
1205
|
def same(a: Rung, b: Rung) -> bool:
|
|
1071
|
-
return a.candidate.model_id == b.candidate.model_id and a.
|
|
1206
|
+
return a.candidate.model_id == b.candidate.model_id and a.level == b.level
|
|
1072
1207
|
|
|
1073
1208
|
cost_rung = rung("cost", span[0])
|
|
1074
1209
|
quality_rung = rung("quality", top)
|
|
@@ -1086,23 +1221,78 @@ def ladder(
|
|
|
1086
1221
|
(r for r in options if not same(r, cost_rung) and not same(r, quality_rung)),
|
|
1087
1222
|
options[0],
|
|
1088
1223
|
)
|
|
1089
|
-
balanced_rung = _below(balanced_rung, quality_rung)
|
|
1090
|
-
cost_rung = _below(cost_rung, balanced_rung)
|
|
1091
|
-
|
|
1092
|
-
|
|
1224
|
+
balanced_rung = _below(balanced_rung, quality_rung, cat)
|
|
1225
|
+
cost_rung = _below(cost_rung, balanced_rung, cat)
|
|
1226
|
+
pool = funded or ranking.candidates
|
|
1227
|
+
rungs = {
|
|
1228
|
+
r.tier: replace(r, backup=_backup_for(r, pool, task, headroom, bench, cat))
|
|
1229
|
+
for r in (cost_rung, balanced_rung, quality_rung)
|
|
1230
|
+
}
|
|
1231
|
+
warning: str | None = None
|
|
1232
|
+
if any(r.backup is None for r in rungs.values()):
|
|
1233
|
+
makers = sorted({c.provider for c in pool})
|
|
1234
|
+
warning = (
|
|
1235
|
+
f"No cross-provider backup: the models this user can run come from "
|
|
1236
|
+
f"{', '.join(makers) or 'no maker'} only. Add a second maker's subscription or "
|
|
1237
|
+
"API key so an outage or an exhausted pool has somewhere to go."
|
|
1238
|
+
)
|
|
1239
|
+
return Ladder(task=base, frontier=front, adequate=adequate, rungs=rungs, backup_warning=warning)
|
|
1240
|
+
|
|
1241
|
+
|
|
1242
|
+
def _backup_for(
|
|
1243
|
+
rung: Rung,
|
|
1244
|
+
pool: list[Candidate],
|
|
1245
|
+
task: Task,
|
|
1246
|
+
headroom: str,
|
|
1247
|
+
bench: dict[str, Any],
|
|
1248
|
+
catalog: dict[str, Any],
|
|
1249
|
+
) -> Backup | None:
|
|
1250
|
+
"""The rung's backup: the best substitute from another maker the operator
|
|
1251
|
+
can run, at no higher list price.
|
|
1252
|
+
|
|
1253
|
+
Over the pool's models from a maker other than the rung model's, draw the
|
|
1254
|
+
frontier and keep its adequate points. The backup is the adequate point
|
|
1255
|
+
with the highest list price at or below the rung's; else the cheapest
|
|
1256
|
+
adequate point above it; else, with no adequate point, the frontier's
|
|
1257
|
+
strongest for the category. It runs at the rung's posture's effort on its
|
|
1258
|
+
own platform. None when the pool holds no other maker's model."""
|
|
1259
|
+
front = frontier([c for c in pool if c.provider != rung.candidate.provider], bench)
|
|
1260
|
+
if not front:
|
|
1261
|
+
return None
|
|
1262
|
+
adequate = [p for p in front if p.candidate.requirement_penalty == 0]
|
|
1263
|
+
if adequate:
|
|
1264
|
+
within = [p for p in adequate if p.price_usd <= rung.point.price_usd]
|
|
1265
|
+
chosen = within[-1] if within else adequate[0]
|
|
1266
|
+
else:
|
|
1267
|
+
chosen = max(front, key=lambda p: (p.candidate.quality, p.aa_index, -p.price_usd))
|
|
1268
|
+
t = Task(task.category, task.complexity, task.novel, TIER_BUDGET[rung.tier])
|
|
1269
|
+
c = chosen.candidate
|
|
1270
|
+
effort = effort_for(t, headroom, c.scarcity)
|
|
1271
|
+
return Backup(chosen, effort, native_level(c.platform_id, c.model_id, effort, catalog=catalog))
|
|
1093
1272
|
|
|
1094
1273
|
|
|
1095
|
-
def _below(lower: Rung, upper: Rung) -> Rung:
|
|
1274
|
+
def _below(lower: Rung, upper: Rung, catalog: dict[str, Any]) -> Rung:
|
|
1096
1275
|
"""``lower`` run at least one effort level below ``upper`` when both name
|
|
1097
1276
|
the same model on the same platform and that path costs something
|
|
1098
1277
|
(scarcity > 0); floored at the dial's lowest level, where the two may
|
|
1099
1278
|
converge. Three columns that read the same offer no choice, and on a
|
|
1100
1279
|
capped pool a lower effort is a real, cheaper option. On a free path
|
|
1101
1280
|
(`uncapped`) a lower effort saves nothing, so the rungs keep their
|
|
1102
|
-
posture's effort and converge.
|
|
1281
|
+
posture's effort and converge.
|
|
1282
|
+
|
|
1283
|
+
Levels are compared on the platform's own dial where the catalog
|
|
1284
|
+
documents one, since two scorer levels can land on one native level
|
|
1285
|
+
(Gemini's dial tops out at high, where the scorer's xhigh and max land
|
|
1286
|
+
too); elsewhere on the scorer's ladder."""
|
|
1103
1287
|
lc, uc = lower.candidate, upper.candidate
|
|
1104
1288
|
if (lc.model_id, lc.platform_id) != (uc.model_id, uc.platform_id) or lc.scarcity == 0:
|
|
1105
1289
|
return lower
|
|
1290
|
+
levels = native_levels(lc.platform_id, lc.model_id, catalog=catalog)
|
|
1291
|
+
if levels and lower.native in levels and upper.native in levels:
|
|
1292
|
+
cap = max(0, levels.index(upper.native) - 1)
|
|
1293
|
+
if levels.index(lower.native) <= cap:
|
|
1294
|
+
return lower
|
|
1295
|
+
return Rung(lower.tier, lower.point, _scorer_level(levels[cap]), levels[cap])
|
|
1106
1296
|
cap = max(0, EFFORT_LADDER.index(upper.effort) - 1)
|
|
1107
1297
|
if EFFORT_LADDER.index(lower.effort) <= cap:
|
|
1108
1298
|
return lower
|
|
@@ -1165,14 +1355,19 @@ def render_ladder_table(table: dict[str, Ladder]) -> str:
|
|
|
1165
1355
|
for p in any_ladder.frontier
|
|
1166
1356
|
),
|
|
1167
1357
|
"Rows: <category>/<complexity>[/novel]: COST | BALANCED | QUALITY, each "
|
|
1168
|
-
"<model> @ <platform> · <effort
|
|
1358
|
+
"<model> @ <platform> · <effort>, the effort in the platform's own level words, "
|
|
1359
|
+
"then `backup <model> @ <platform>`: that pick's BACKUP.",
|
|
1169
1360
|
]
|
|
1361
|
+
|
|
1362
|
+
def cell(t: str, r: Rung) -> str:
|
|
1363
|
+
text = f"{t.upper()} = {r.candidate.model_name} @ {r.candidate.platform_name} · {r.level}"
|
|
1364
|
+
if r.backup is not None:
|
|
1365
|
+
b = r.backup.candidate
|
|
1366
|
+
text += f", backup {b.model_name} @ {b.platform_name}"
|
|
1367
|
+
return text
|
|
1368
|
+
|
|
1170
1369
|
for key, lad in table.items():
|
|
1171
|
-
cells = " | ".join(
|
|
1172
|
-
f"{t.upper()} = {r.candidate.model_name} @ {r.candidate.platform_name} · {r.effort}"
|
|
1173
|
-
for t in LADDER_TIERS
|
|
1174
|
-
for r in [lad.rungs[t]]
|
|
1175
|
-
)
|
|
1370
|
+
cells = " | ".join(cell(t, lad.rungs[t]) for t in LADDER_TIERS)
|
|
1176
1371
|
lines.append(f"{key}: {cells}")
|
|
1177
1372
|
lines.append("</ladder-table>")
|
|
1178
1373
|
return "\n".join(lines)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|