@@ -219,29 +219,65 @@ function populateModelSelect(models, defaultModel = null, provider = 'ollama') {
219219 }
220220 modelSelect . appendChild ( option ) ;
221221 } ) ;
222- } else if ( provider === 'openrouter' ) {
222+ } else if ( provider === 'openrouter' || provider === 'poe' ) {
223+ // OpenRouter and Poe share the same pricing display format
224+ // Poe additionally supports grouping by owned_by and request-based pricing
225+ let currentGroup = null ;
226+ let optgroup = null ;
227+
223228 models . forEach ( model => {
229+ // For Poe: group by owned_by or fallback group
230+ if ( provider === 'poe' ) {
231+ const groupKey = model . group || model . owned_by ;
232+ if ( groupKey && groupKey !== currentGroup ) {
233+ currentGroup = groupKey ;
234+ optgroup = document . createElement ( 'optgroup' ) ;
235+ optgroup . label = currentGroup ;
236+ modelSelect . appendChild ( optgroup ) ;
237+ }
238+ }
239+
224240 const option = document . createElement ( 'option' ) ;
225- // Handle both API response format (id) and fallback format (value)
226241 const modelId = model . id || model . value ;
227242 option . value = modelId ;
228243
229244 // Format label with pricing info if available
230- if ( model . pricing && model . pricing . prompt_per_million !== undefined ) {
231- const inputPrice = formatPrice ( model . pricing . prompt_per_million ) ;
232- const outputPrice = formatPrice ( model . pricing . completion_per_million ) ;
233- option . textContent = `${ model . name || modelId } (In: ${ inputPrice } /M, Out: ${ outputPrice } /M)` ;
234- option . title = `Context: ${ model . context_length || 'N/A' } tokens` ;
245+ if ( model . pricing && ( model . pricing . prompt_per_million !== undefined || model . pricing . request ) ) {
246+ if ( model . pricing . request && model . pricing . request > 0 ) {
247+ // Request-based pricing (Poe specific)
248+ option . textContent = `${ model . name || modelId } ($${ model . pricing . request . toFixed ( 4 ) } /req)` ;
249+ } else {
250+ // Token-based pricing (shared format)
251+ const inputPrice = formatPrice ( model . pricing . prompt_per_million ) ;
252+ const outputPrice = formatPrice ( model . pricing . completion_per_million ) ;
253+ option . textContent = `${ model . name || modelId } (In: ${ inputPrice } /M, Out: ${ outputPrice } /M)` ;
254+ }
235255 } else {
236- // Fallback format
256+ // Fallback format (no pricing)
237257 option . textContent = model . label || model . name || modelId ;
238258 }
239259
260+ // Build tooltip
261+ let tooltip = [ ] ;
262+ if ( model . context_length ) {
263+ tooltip . push ( `Context: ${ model . context_length } tokens` ) ;
264+ }
265+ if ( model . description ) {
266+ tooltip . push ( model . description ) ;
267+ }
268+ option . title = tooltip . length > 0 ? tooltip . join ( ' | ' ) : '' ;
269+
240270 if ( modelId === defaultModel ) {
241271 option . selected = true ;
242272 defaultModelFound = true ;
243273 }
244- modelSelect . appendChild ( option ) ;
274+
275+ // Add to optgroup if exists (Poe), otherwise to select
276+ if ( optgroup ) {
277+ optgroup . appendChild ( option ) ;
278+ } else {
279+ modelSelect . appendChild ( option ) ;
280+ }
245281 } ) ;
246282 } else if ( provider === 'mistral' ) {
247283 models . forEach ( model => {
@@ -271,73 +307,6 @@ function populateModelSelect(models, defaultModel = null, provider = 'ollama') {
271307 }
272308 modelSelect . appendChild ( option ) ;
273309 } ) ;
274- } else if ( provider === 'poe' ) {
275- // Poe models - support groups for fallback, pricing for API response
276- let currentGroup = null ;
277- let optgroup = null ;
278-
279- models . forEach ( model => {
280- // Create optgroup if group changed (for fallback models with groups)
281- if ( model . group && model . group !== currentGroup ) {
282- currentGroup = model . group ;
283- optgroup = document . createElement ( 'optgroup' ) ;
284- optgroup . label = currentGroup ;
285- modelSelect . appendChild ( optgroup ) ;
286- }
287-
288- // For API response models, group by owned_by
289- if ( ! model . group && model . owned_by && model . owned_by !== currentGroup ) {
290- currentGroup = model . owned_by ;
291- optgroup = document . createElement ( 'optgroup' ) ;
292- optgroup . label = currentGroup ;
293- modelSelect . appendChild ( optgroup ) ;
294- }
295-
296- const option = document . createElement ( 'option' ) ;
297- const modelId = model . value || model . id ;
298- option . value = modelId ;
299-
300- // Format label with pricing info if available (from API)
301- if ( model . pricing && ( model . pricing . prompt_per_million !== undefined || model . pricing . request ) ) {
302- if ( model . pricing . request ) {
303- // Request-based pricing
304- const requestPrice = model . pricing . request ;
305- option . textContent = `${ model . label || model . name || modelId } ($${ requestPrice . toFixed ( 4 ) } /req)` ;
306- } else {
307- // Token-based pricing
308- const inputPrice = formatPrice ( model . pricing . prompt_per_million ) ;
309- const outputPrice = formatPrice ( model . pricing . completion_per_million ) ;
310- option . textContent = `${ model . label || model . name || modelId } (In: ${ inputPrice } /M, Out: ${ outputPrice } /M)` ;
311- }
312- } else {
313- // Fallback format (no pricing)
314- option . textContent = model . label || model . name || modelId ;
315- }
316-
317- // Build tooltip with context and description
318- let tooltip = [ ] ;
319- if ( model . context_length ) {
320- tooltip . push ( `Context: ${ model . context_length } tokens` ) ;
321- }
322- if ( model . description ) {
323- tooltip . push ( model . description ) ;
324- }
325- if ( tooltip . length > 0 ) {
326- option . title = tooltip . join ( ' | ' ) ;
327- }
328-
329- if ( modelId === defaultModel ) {
330- option . selected = true ;
331- defaultModelFound = true ;
332- }
333-
334- // Add to optgroup if exists, otherwise to select
335- if ( optgroup ) {
336- optgroup . appendChild ( option ) ;
337- } else {
338- modelSelect . appendChild ( option ) ;
339- }
340- } ) ;
341310 } else {
342311 // Ollama - models are strings
343312 models . forEach ( modelName => {
@@ -1035,20 +1004,14 @@ export const ProviderManager = {
10351004 if ( data . models && data . models . length > 0 ) {
10361005 MessageLogger . showMessage ( '' , '' ) ;
10371006
1038- // Format models for the dropdown
1039- const formattedModels = data . models . map ( m => ( {
1040- value : m . id ,
1041- label : m . name || m . id ,
1042- context_length : m . context_length
1043- } ) ) ;
1044-
1045- populateModelSelect ( formattedModels , data . default , 'poe' ) ;
1046- MessageLogger . addLog ( `${ data . count } Poe model(s) loaded` ) ;
1007+ // Pass models directly (same format as OpenRouter)
1008+ populateModelSelect ( data . models , data . default , 'poe' ) ;
1009+ MessageLogger . addLog ( `${ data . count } Poe model(s) loaded (sorted by provider)` ) ;
10471010
10481011 SettingsManager . applyPendingModelSelection ( ) ;
10491012 ModelDetector . checkAndShowRecommendation ( ) ;
10501013
1051- StateManager . setState ( 'models.availableModels' , formattedModels . map ( m => m . value ) ) ;
1014+ StateManager . setState ( 'models.availableModels' , data . models . map ( m => m . id ) ) ;
10521015 StatusManager . setConnected ( 'poe' , data . count ) ;
10531016 } else {
10541017 // Use fallback list
0 commit comments