@@ -76,6 +76,14 @@ export const ModelSelectionButton: React.FC<{}> = ({ }) => {
76
76
const [ modelDialogOpen , setModelDialogOpen ] = useState < boolean > ( false ) ;
77
77
const [ showKeys , setShowKeys ] = useState < boolean > ( false ) ;
78
78
const [ tempSelectedModelId , setTempSelectedModeId ] = useState < string | undefined > ( selectedModelId ) ;
79
+ const [ providerModelOptions , setProviderModelOptions ] = useState < { [ key : string ] : string [ ] } > ( {
80
+ 'openai' : [ ] ,
81
+ 'azure' : [ ] ,
82
+ 'anthropic' : [ ] ,
83
+ 'gemini' : [ ] ,
84
+ 'ollama' : [ ]
85
+ } ) ;
86
+ const [ isLoadingModelOptions , setIsLoadingModelOptions ] = useState < boolean > ( false ) ;
79
87
80
88
let updateModelStatus = ( model : ModelConfig , status : 'ok' | 'error' | 'testing' | 'unknown' , message : string ) => {
81
89
dispatch ( dfActions . updateModelStatus ( { id : model . id , status, message} ) ) ;
@@ -90,23 +98,60 @@ export const ModelSelectionButton: React.FC<{}> = ({ }) => {
90
98
const [ newApiBase , setNewApiBase ] = useState < string | undefined > ( undefined ) ;
91
99
const [ newApiVersion , setNewApiVersion ] = useState < string | undefined > ( undefined ) ;
92
100
101
+ // Fetch available models from the API
102
+ useEffect ( ( ) => {
103
+ const fetchModelOptions = async ( ) => {
104
+ setIsLoadingModelOptions ( true ) ;
105
+ try {
106
+ const response = await fetch ( getUrls ( ) . CHECK_AVAILABLE_MODELS ) ;
107
+ const data = await response . json ( ) ;
108
+
109
+ // Group models by provider
110
+ const modelsByProvider : { [ key : string ] : string [ ] } = {
111
+ 'openai' : [ ] ,
112
+ 'azure' : [ ] ,
113
+ 'anthropic' : [ ] ,
114
+ 'gemini' : [ ] ,
115
+ 'ollama' : [ ]
116
+ } ;
117
+
118
+ data . forEach ( ( modelConfig : any ) => {
119
+ const provider = modelConfig . endpoint ;
120
+ const model = modelConfig . model ;
121
+
122
+ if ( provider && model && ! modelsByProvider [ provider ] . includes ( model ) ) {
123
+ modelsByProvider [ provider ] . push ( model ) ;
124
+ }
125
+ } ) ;
126
+
127
+ setProviderModelOptions ( modelsByProvider ) ;
128
+ } catch ( error ) {
129
+ console . error ( "Failed to fetch model options:" , error ) ;
130
+ } finally {
131
+ setIsLoadingModelOptions ( false ) ;
132
+ }
133
+ } ;
134
+
135
+ fetchModelOptions ( ) ;
136
+ } , [ ] ) ;
137
+
93
138
useEffect ( ( ) => {
94
139
if ( newEndpoint == 'ollama' ) {
95
140
if ( ! newApiBase ) {
96
141
setNewApiBase ( 'http://localhost:11434' ) ;
97
142
}
98
143
}
99
144
if ( newEndpoint == "openai" ) {
100
- if ( ! newModel ) {
101
- setNewModel ( 'gpt-4o' ) ;
145
+ if ( ! newModel && providerModelOptions . openai . length > 0 ) {
146
+ setNewModel ( providerModelOptions . openai [ 0 ] ) ;
102
147
}
103
148
}
104
149
if ( newEndpoint == "anthropic" ) {
105
- if ( ! newModel ) {
106
- setNewModel ( 'claude-3-5-sonnet-20241022' ) ;
150
+ if ( ! newModel && providerModelOptions . anthropic . length > 0 ) {
151
+ setNewModel ( providerModelOptions . anthropic [ 0 ] ) ;
107
152
}
108
153
}
109
- } , [ newEndpoint ] ) ;
154
+ } , [ newEndpoint , providerModelOptions ] ) ;
110
155
111
156
let modelExists = models . some ( m =>
112
157
m . endpoint == newEndpoint && m . model == newModel && m . api_base == newApiBase
@@ -150,8 +195,8 @@ export const ModelSelectionButton: React.FC<{}> = ({ }) => {
150
195
value = { newEndpoint }
151
196
onChange = { ( event : any , newValue : string | null ) => {
152
197
setNewEndpoint ( newValue || "" ) ;
153
- if ( newModel == "" && newValue == "openai" ) {
154
- setNewModel ( "gpt-4o" ) ;
198
+ if ( newModel == "" && newValue == "openai" && providerModelOptions . openai . length > 0 ) {
199
+ setNewModel ( providerModelOptions . openai [ 0 ] ) ;
155
200
}
156
201
if ( ! newApiVersion && newValue == "azure" ) {
157
202
setNewApiVersion ( "2024-02-15" ) ;
@@ -202,7 +247,8 @@ export const ModelSelectionButton: React.FC<{}> = ({ }) => {
202
247
freeSolo
203
248
onChange = { ( event : any , newValue : string | null ) => { setNewModel ( newValue || "" ) ; } }
204
249
value = { newModel }
205
- options = { [ 'gpt-4o-mini' , 'gpt-4o' , 'claude-3-5-sonnet-20241022' ] }
250
+ options = { newEndpoint && providerModelOptions [ newEndpoint ] ? providerModelOptions [ newEndpoint ] : [ ] }
251
+ loading = { isLoadingModelOptions }
206
252
renderOption = { ( props , option ) => {
207
253
return < Typography { ...props } onClick = { ( ) => { setNewModel ( option ) ; } } sx = { { fontSize : "small" } } > { option } </ Typography >
208
254
} }
@@ -211,7 +257,16 @@ export const ModelSelectionButton: React.FC<{}> = ({ }) => {
211
257
error = { newEndpoint != "" && ! newModel }
212
258
{ ...params }
213
259
placeholder = "model name"
214
- InputProps = { { ...params . InputProps , style : { fontSize : "0.875rem" } } }
260
+ InputProps = { {
261
+ ...params . InputProps ,
262
+ style : { fontSize : "0.875rem" } ,
263
+ endAdornment : (
264
+ < >
265
+ { isLoadingModelOptions ? < CircularProgress color = "inherit" size = { 20 } /> : null }
266
+ { params . InputProps . endAdornment }
267
+ </ >
268
+ ) ,
269
+ } }
215
270
inputProps = { {
216
271
...params . inputProps ,
217
272
'aria-label' : 'Select or enter a model' ,
@@ -226,7 +281,7 @@ export const ModelSelectionButton: React.FC<{}> = ({ }) => {
226
281
PaperComponent = { ( { children } ) => (
227
282
< Paper >
228
283
< Typography sx = { { p : 1 , color : 'gray' , fontStyle : 'italic' , fontSize : 'small' } } >
229
- examples
284
+ { isLoadingModelOptions ? 'Loading models...' : ' examples' }
230
285
</ Typography >
231
286
{ children }
232
287
</ Paper >
0 commit comments