feat: add per-model default and max reasoning effort with per-turn selection - #26970
Closed
DanielleMaywood wants to merge 4 commits into
Closed
feat: add per-model default and max reasoning effort with per-turn selection#26970DanielleMaywood wants to merge 4 commits into
DanielleMaywood wants to merge 4 commits into
Conversation
…lection Replace the fixed per-provider reasoning effort in chat model configs with a default/max pair, migrate existing values so the old effort becomes both, and let users pick the per-turn effort with a slider in the chat model selector, clamped to the model's max.
Contributor
Docs preview📖 View docs preview for |
… models page Migration 000536 collided with main's ai_user_daily_spend migration. The default and max reasoning effort selects now render in the always-visible section of the model form instead of under Advanced.
Make the effort data migration provider-aware, allow configuring none where the provider runtime supports it, fail model config updates when the provider is soft-deleted, preserve a message's original effort on edit unless the user changes it, and trim unused helpers and redundant tests.
Contributor
Author
|
Split into a stacked series per review feedback: #26974 (model config default/max + migration) -> #26975 (per-turn API) -> #26976 (models page UI, on #26974) and #26977 (chat slider, on #26975). The combined content of the stack is identical to this branch. 🤖 Generated by Coder Agents on behalf of @DanielleMaywood |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Reasoning effort was a fixed per-model setting stored at provider-specific paths in
chat_model_configs.options, so offering the same model at multiple efforts required duplicate model configs. Each model config now carries areasoning_effort{default, max}pair, and the chat model selector gains an effort slider so users pick the per-turn effort, clamped to the model's max.Changes
ChatModelReasoningEffortConfig(default/max) onChatModelCallConfig; the per-provider effort fields (openai.reasoning_effort,anthropic.effort,openaicompat.reasoning_effort,openrouter/vercelreasoning.effort) are removed.CreateChatRequest,CreateChatMessageRequest, andEditChatMessageRequestgainreasoning_effortfor the per-turn selection, andChatexposeslast_reasoning_effort.chats.last_reasoning_effort,chat_messages.reasoning_effort, andchat_queued_messages.reasoning_effort; rewriteschat_model_configs.optionsso the legacy per-provider effort value becomes bothdefaultandmax, stripping the legacy keys. Down migration restores the provider-appropriate path viaai_providers.type.chats.last_reasoning_effort(mirroringlast_model_config_id). At generation,chatprovider.ResolveReasoningEffortpicks the requested value (else the config default), clamps to the config max on the global scalenone < minimal < low < medium < high < xhigh < max, and snaps into the provider's runtime-supported set before injecting it into the fantasy provider options. Documented incoderd/x/chatd/ARCHITECTURE.md.default <= maxvalidation. Known-model catalog defaults now populate the new pair.Validation: config values must be in the provider's supported set with
default <= max; per-turn values are validated against the global scale (400 otherwise) and re-clamped server-side at generation.Implementation plan
Effort scale
One global ordered scale used for clamping and the slider:
minimal < low < medium < high < xhigh < max("none" normalizes to unset everywhere). Provider-supported sets follow the existing runtime normalization: openai/openaicompatminimal..xhigh, anthropiclow..max, openrouterlow..high, vercelnone..xhigh.Model config schema (codersdk)
Replace the five per-provider effort fields with one top-level
ChatModelReasoningEffortConfig { default, max }onChatModelCallConfig. Backend validation: both values in the provider's supported set,default <= max, single value mirrors into the other.Per-turn effort selection
Mirror the existing
model_config_idflow:reasoning_efforton create/edit message requests, nullable columns onchat_messagesandchat_queued_messages,chats.last_reasoning_effortupdated byInsertChatMessagesfrom the last message carrying one (so queued messages promote correctly).Generation resolution
In
prepareGeneration: effective = user-selected (chats.last_reasoning_effort) else config default; clamped to config max on the global scale; normalized/snapped into the provider's supported range; injected into the provider-native fantasy options. Models without effort config ignore user values.Migration
One migration adds the three columns and rewrites
chat_model_configs.options:COALESCEacross the five legacy provider effort paths becomesreasoning_effort {default: v, max: v}, legacy keys stripped. Down migration reverses via theai_providersjoin.Frontend
Model selector dropdown gets a bottom Effort row (label + info tooltip, shared
Slider, value badge) shown only when the selected model has effort configured; steps span the provider's supported values up to the model's max; re-clamps on model switch; value sent with each message and on chat creation. Admin panel gets Default/Max effort selects replacing the per-provider selects.Tests
Go: migration fixture for the JSONB rewrite, clamp/resolution unit tests, handler validation tests, send/create persistence tests. Frontend: vitest for pure effort helpers and form logic, Storybook play tests for the slider row and create form.
🤖 Generated by Coder Agents on behalf of @DanielleMaywood