@@ -27,6 +27,12 @@ import {
2727 minimaxModels ,
2828 friendliDefaultModelId ,
2929 friendliModels ,
30+ fireworksDefaultModelId ,
31+ fireworksModels ,
32+ basetenDefaultModelId ,
33+ basetenModels ,
34+ sambaNovaDefaultModelId ,
35+ sambaNovaModels ,
3036 deepSeekDefaultModelId ,
3137 deepSeekModels ,
3238 openRouterDefaultModelId ,
@@ -1490,6 +1496,109 @@ describe("useSelectedModel", () => {
14901496 } )
14911497 } )
14921498
1499+ describe ( "OpenAI-compatible static catalog providers (fireworks, baseten, sambanova)" , ( ) => {
1500+ beforeEach ( ( ) => {
1501+ mockUseRouterModels . mockReturnValue ( createRouterModelsResult ( { openrouter : { } , requesty : { } , litellm : { } } ) )
1502+ mockUseOpenRouterModelProviders . mockReturnValue ( createOpenRouterModelProvidersResult ( { } ) )
1503+ } )
1504+
1505+ it ( "returns the default Fireworks model when no model is configured" , ( ) => {
1506+ const { result } = renderHook ( ( ) => useSelectedModel ( { apiProvider : providerIdentifiers . fireworks } ) , {
1507+ wrapper : createWrapper ( ) ,
1508+ } )
1509+
1510+ expect ( result . current . id ) . toBe ( fireworksDefaultModelId )
1511+ expect ( result . current . info ) . toEqual ( fireworksModels [ fireworksDefaultModelId ] )
1512+ } )
1513+
1514+ it ( "returns known Fireworks model metadata" , ( ) => {
1515+ const id = "accounts/fireworks/models/kimi-k2-instruct"
1516+ const { result } = renderHook (
1517+ ( ) => useSelectedModel ( { apiProvider : providerIdentifiers . fireworks , apiModelId : id } ) ,
1518+ { wrapper : createWrapper ( ) } ,
1519+ )
1520+
1521+ expect ( result . current . id ) . toBe ( id )
1522+ expect ( result . current . info ) . toEqual ( fireworksModels [ id ] )
1523+ } )
1524+
1525+ const staticCatalogCases = [
1526+ {
1527+ apiProvider : providerIdentifiers . fireworks ,
1528+ defaultId : fireworksDefaultModelId ,
1529+ models : fireworksModels as Record < string , ModelInfo > ,
1530+ knownId : "accounts/fireworks/models/kimi-k2-instruct" ,
1531+ } ,
1532+ {
1533+ apiProvider : providerIdentifiers . baseten ,
1534+ defaultId : basetenDefaultModelId ,
1535+ models : basetenModels as Record < string , ModelInfo > ,
1536+ knownId : Object . keys ( basetenModels ) . find ( ( id ) => id !== basetenDefaultModelId ) ! ,
1537+ } ,
1538+ {
1539+ apiProvider : providerIdentifiers . sambanova ,
1540+ defaultId : sambaNovaDefaultModelId ,
1541+ models : sambaNovaModels as Record < string , ModelInfo > ,
1542+ knownId : Object . keys ( sambaNovaModels ) . find ( ( id ) => id !== sambaNovaDefaultModelId ) ! ,
1543+ } ,
1544+ ]
1545+
1546+ it . each ( staticCatalogCases ) (
1547+ "returns the default $apiProvider model when no model is configured" ,
1548+ ( { apiProvider, defaultId, models } ) => {
1549+ const { result } = renderHook ( ( ) => useSelectedModel ( { apiProvider } ) , { wrapper : createWrapper ( ) } )
1550+
1551+ expect ( result . current . provider ) . toBe ( apiProvider )
1552+ expect ( result . current . id ) . toBe ( defaultId )
1553+ expect ( result . current . info ) . toEqual ( models [ defaultId ] )
1554+ expect ( result . current . info ) . toBeDefined ( )
1555+ } ,
1556+ )
1557+
1558+ it . each ( staticCatalogCases ) (
1559+ "falls back to the default $apiProvider model when apiModelId is an empty string" ,
1560+ ( { apiProvider, defaultId, models } ) => {
1561+ const { result } = renderHook ( ( ) => useSelectedModel ( { apiProvider, apiModelId : "" } ) , {
1562+ wrapper : createWrapper ( ) ,
1563+ } )
1564+
1565+ expect ( result . current . id ) . toBe ( defaultId )
1566+ expect ( result . current . info ) . toEqual ( models [ defaultId ] )
1567+ expect ( result . current . info ) . toBeDefined ( )
1568+ } ,
1569+ )
1570+
1571+ it . each ( staticCatalogCases ) (
1572+ "returns known $apiProvider catalog metadata" ,
1573+ ( { apiProvider, models, knownId } ) => {
1574+ expect ( knownId ) . toBeDefined ( )
1575+ const { result } = renderHook ( ( ) => useSelectedModel ( { apiProvider, apiModelId : knownId } ) , {
1576+ wrapper : createWrapper ( ) ,
1577+ } )
1578+
1579+ expect ( result . current . provider ) . toBe ( apiProvider )
1580+ expect ( result . current . id ) . toBe ( knownId )
1581+ expect ( result . current . info ) . toEqual ( models [ knownId ] )
1582+ } ,
1583+ )
1584+
1585+ it . each ( [ providerIdentifiers . fireworks , providerIdentifiers . baseten , providerIdentifiers . sambanova ] ) (
1586+ "honors a custom %s model ID with sane default metadata (not undefined info)" ,
1587+ ( apiProvider ) => {
1588+ // Regression: custom models had undefined info, so the task header fell back to a
1589+ // context window of 1. The backend uses openAiModelInfoSaneDefaults, so the UI must too.
1590+ const { result } = renderHook (
1591+ ( ) => useSelectedModel ( { apiProvider, apiModelId : "some/custom-model-not-in-list" } ) ,
1592+ { wrapper : createWrapper ( ) } ,
1593+ )
1594+
1595+ expect ( result . current . id ) . toBe ( "some/custom-model-not-in-list" )
1596+ expect ( result . current . info ) . toEqual ( openAiModelInfoSaneDefaults )
1597+ expect ( result . current . info ?. contextWindow ) . toBeGreaterThan ( 1 )
1598+ } ,
1599+ )
1600+ } )
1601+
14931602 describe ( "Z AI provider" , ( ) => {
14941603 it ( "uses the International Coding catalog when no API line is configured" , ( ) => {
14951604 const apiConfiguration : ProviderSettings = {
0 commit comments