@@ -2,12 +2,13 @@ import { createFileRoute } from "@tanstack/react-router";
22import { useQuery } from "@tanstack/react-query" ;
33import { useCallback , useState } from "react" ;
44import {
5+ type ModelSlug ,
56 type ProviderKind ,
67 DEFAULT_GIT_TEXT_GENERATION_MODEL_BY_PROVIDER ,
78} from "@t3tools/contracts" ;
89import { getModelOptions , normalizeModelSlug } from "@t3tools/shared/model" ;
910import {
10- getAppModelOptions ,
11+ getCustomModelOptionsByProvider ,
1112 getCustomModelsForProvider ,
1213 getDefaultCustomModelsForProvider ,
1314 MAX_CUSTOM_MODEL_LENGTH ,
@@ -31,6 +32,7 @@ import {
3132} from "../components/ui/select" ;
3233import { Switch } from "../components/ui/switch" ;
3334import { APP_VERSION } from "../branding" ;
35+ import { ProviderModelPicker } from "../components/chat/ProviderModelPicker" ;
3436import { SidebarInset } from "~/components/ui/sidebar" ;
3537
3638const THEME_OPTIONS = [
@@ -80,16 +82,8 @@ function SettingsRouteView() {
8082
8183 const textGenProvider = settings . textGenerationProvider ;
8284 const textGenDefaultModel = DEFAULT_GIT_TEXT_GENERATION_MODEL_BY_PROVIDER [ textGenProvider ] ;
83- const gitTextGenerationModelOptions = getAppModelOptions (
84- textGenProvider ,
85- textGenProvider === "codex" ? settings . customCodexModels : settings . customClaudeModels ,
86- settings . textGenerationModel ,
87- ) ;
88- const selectedGitTextGenerationModelLabel =
89- gitTextGenerationModelOptions . find (
90- ( option ) =>
91- option . slug === ( settings . textGenerationModel ?? textGenDefaultModel ) ,
92- ) ?. name ?? settings . textGenerationModel ;
85+ const textGenModel = ( settings . textGenerationModel ?? textGenDefaultModel ) as ModelSlug ;
86+ const gitModelOptionsByProvider = getCustomModelOptionsByProvider ( settings ) ;
9387
9488 const openKeybindingsFile = useCallback ( ( ) => {
9589 if ( ! keybindingsConfigPath ) return ;
@@ -490,75 +484,27 @@ function SettingsRouteView() {
490484 </ p >
491485 </ div >
492486
493- < div className = "flex flex-col gap-4" >
494- < div className = "flex flex-col gap-4 rounded-lg border border-border bg-background px-3 py-3 sm:flex-row sm:items-center sm:justify-between" >
495- < div className = "min-w-0 flex-1" >
496- < p className = "text-sm font-medium text-foreground" >
497- Text generation provider
498- </ p >
499- < p className = "text-xs text-muted-foreground" >
500- Which AI provider to use for auto-generated git content.
501- </ p >
502- </ div >
503- < Select
504- value = { textGenProvider }
505- onValueChange = { ( value ) => {
506- if ( value === "codex" || value === "claudeAgent" ) {
507- updateSettings ( {
508- textGenerationProvider : value ,
509- textGenerationModel :
510- DEFAULT_GIT_TEXT_GENERATION_MODEL_BY_PROVIDER [ value ] ,
511- } ) ;
512- }
513- } }
514- >
515- < SelectTrigger
516- className = "w-full shrink-0 sm:w-48"
517- aria-label = "Git text generation provider"
518- >
519- < SelectValue >
520- { textGenProvider === "claudeAgent" ? "Claude" : "Codex" }
521- </ SelectValue >
522- </ SelectTrigger >
523- < SelectPopup align = "end" >
524- < SelectItem value = "codex" > Codex</ SelectItem >
525- < SelectItem value = "claudeAgent" > Claude</ SelectItem >
526- </ SelectPopup >
527- </ Select >
528- </ div >
529-
530- < div className = "flex flex-col gap-4 rounded-lg border border-border bg-background px-3 py-3 sm:flex-row sm:items-center sm:justify-between" >
531- < div className = "min-w-0 flex-1" >
532- < p className = "text-sm font-medium text-foreground" > Text generation model</ p >
533- < p className = "text-xs text-muted-foreground" >
534- Model used for auto-generated git content.
535- </ p >
536- </ div >
537- < Select
538- value = { settings . textGenerationModel ?? textGenDefaultModel }
539- onValueChange = { ( value ) => {
540- if ( value ) {
541- updateSettings ( {
542- textGenerationModel : value ,
543- } ) ;
544- }
545- } }
546- >
547- < SelectTrigger
548- className = "w-full shrink-0 sm:w-48"
549- aria-label = "Git text generation model"
550- >
551- < SelectValue > { selectedGitTextGenerationModelLabel } </ SelectValue >
552- </ SelectTrigger >
553- < SelectPopup align = "end" >
554- { gitTextGenerationModelOptions . map ( ( option ) => (
555- < SelectItem key = { option . slug } value = { option . slug } >
556- { option . name }
557- </ SelectItem >
558- ) ) }
559- </ SelectPopup >
560- </ Select >
487+ < div className = "flex flex-col gap-4 rounded-lg border border-border bg-background px-3 py-3 sm:flex-row sm:items-center sm:justify-between" >
488+ < div className = "min-w-0 flex-1" >
489+ < p className = "text-sm font-medium text-foreground" >
490+ Text generation model
491+ </ p >
492+ < p className = "text-xs text-muted-foreground" >
493+ Provider and model used for auto-generated git content.
494+ </ p >
561495 </ div >
496+ < ProviderModelPicker
497+ provider = { textGenProvider }
498+ model = { textGenModel }
499+ lockedProvider = { null }
500+ modelOptionsByProvider = { gitModelOptionsByProvider }
501+ onProviderModelChange = { ( provider , model ) => {
502+ updateSettings ( {
503+ textGenerationProvider : provider ,
504+ textGenerationModel : model ,
505+ } ) ;
506+ } }
507+ />
562508 </ div >
563509
564510 { ( settings . textGenerationModel !== defaults . textGenerationModel ||
0 commit comments