@@ -620,13 +620,15 @@ describe("modelsListCommand forward-compat", () => {
620620 } ) ;
621621 } ) ;
622622
623- it ( "includes configured provider and auth-backed catalog rows in configured- mode lists" , async ( ) => {
623+ function configureAuthenticatedCatalogScenario ( mode : "merge" | "replace" ) {
624624 const config = {
625625 agents : { defaults : { model : { primary : "xiaomi/mimo-v2.5-pro" } } } ,
626626 models : {
627+ mode,
627628 providers : {
628629 xiaomi : {
629- api : "openai-completions" ,
630+ // Replace-mode configured models can rely on runtime transport inference.
631+ ...( mode === "merge" ? { api : "openai-completions" as const } : { } ) ,
630632 apiKey : "tp-fixture" ,
631633 baseUrl : "https://api.xiaomi.example/v1" ,
632634 models : [
@@ -637,12 +639,12 @@ describe("modelsListCommand forward-compat", () => {
637639 } ,
638640 } ,
639641 } ;
640- mocks . loadModelsConfigWithSource . mockResolvedValueOnce ( {
642+ mocks . loadModelsConfigWithSource . mockResolvedValue ( {
641643 sourceConfig : config ,
642644 resolvedConfig : config ,
643645 diagnostics : [ ] ,
644646 } ) ;
645- mocks . ensureAuthProfileStore . mockReturnValueOnce ( {
647+ mocks . ensureAuthProfileStore . mockReturnValue ( {
646648 version : 1 ,
647649 profiles : {
648650 "google:default" : {
@@ -653,7 +655,7 @@ describe("modelsListCommand forward-compat", () => {
653655 } ,
654656 order : { } ,
655657 } ) ;
656- mocks . resolveConfiguredEntries . mockReturnValueOnce ( {
658+ mocks . resolveConfiguredEntries . mockReturnValue ( {
657659 entries : [
658660 {
659661 key : "xiaomi/mimo-v2.5-pro" ,
@@ -663,7 +665,7 @@ describe("modelsListCommand forward-compat", () => {
663665 } ,
664666 ] ,
665667 } ) ;
666- mocks . loadModelCatalog . mockResolvedValueOnce ( [
668+ mocks . loadModelCatalog . mockResolvedValue ( [
667669 {
668670 provider : "google" ,
669671 id : "gemini-3.1-flash-lite" ,
@@ -672,23 +674,92 @@ describe("modelsListCommand forward-compat", () => {
672674 contextWindow : 1_000_000 ,
673675 } ,
674676 ] ) ;
675- const runtime = createRuntime ( ) ;
677+ }
676678
677- await modelsListCommand ( { json : true } , runtime as never ) ;
679+ it . each ( [
680+ {
681+ mode : "merge" ,
682+ expectedKeys : [
683+ "xiaomi/mimo-v2.5-pro" ,
684+ "xiaomi/mimo-v2.5" ,
685+ "google/gemini-3.1-flash-lite" ,
686+ ] ,
687+ } ,
688+ {
689+ mode : "replace" ,
690+ expectedKeys : [ "xiaomi/mimo-v2.5-pro" , "xiaomi/mimo-v2.5" ] ,
691+ } ,
692+ ] as const ) (
693+ "uses $mode catalog semantics for the default list" ,
694+ async ( { mode, expectedKeys } ) => {
695+ configureAuthenticatedCatalogScenario ( mode ) ;
696+ const runtime = createRuntime ( ) ;
678697
679- expect ( mocks . loadModelRegistry ) . not . toHaveBeenCalled ( ) ;
680- const rows = lastPrintedRows < { key : string ; name : string ; available : boolean } > ( ) ;
681- expectRowKeys ( rows , [
682- "xiaomi/mimo-v2.5-pro" ,
683- "xiaomi/mimo-v2.5" ,
684- "google/gemini-3.1-flash-lite" ,
685- ] ) ;
686- expectRowFields ( rows , "xiaomi/mimo-v2.5-pro" , { name : "MiMo V2.5 Pro" } ) ;
687- expectRowFields ( rows , "xiaomi/mimo-v2.5" , { name : "MiMo V2.5" } ) ;
688- expectRowFields ( rows , "google/gemini-3.1-flash-lite" , {
698+ await modelsListCommand ( { json : true } , runtime as never ) ;
699+
700+ expect ( mocks . loadModelRegistry ) . not . toHaveBeenCalled ( ) ;
701+ const rows = lastPrintedRows < { key : string ; name : string ; available : boolean } > ( ) ;
702+ expectRowKeys ( rows , [ ...expectedKeys ] ) ;
703+ expectRowFields ( rows , "xiaomi/mimo-v2.5-pro" , { name : "MiMo V2.5 Pro" } ) ;
704+ expectRowFields ( rows , "xiaomi/mimo-v2.5" , { name : "MiMo V2.5" } ) ;
705+ if ( mode === "merge" ) {
706+ expectRowFields ( rows , "google/gemini-3.1-flash-lite" , {
707+ name : "Gemini 3.1 Flash Lite" ,
708+ available : true ,
709+ } ) ;
710+ expect ( mocks . loadModelCatalog ) . toHaveBeenCalledOnce ( ) ;
711+ } else {
712+ expect ( mocks . loadModelCatalog ) . not . toHaveBeenCalled ( ) ;
713+ }
714+ } ,
715+ ) ;
716+
717+ it ( "preserves explicit all and provider browsing in replace mode" , async ( ) => {
718+ configureAuthenticatedCatalogScenario ( "replace" ) ;
719+ const googleModelKey = "google/gemini-3.1-flash-lite" ;
720+ const googleModel = {
721+ provider : "google" ,
722+ id : "gemini-3.1-flash-lite" ,
689723 name : "Gemini 3.1 Flash Lite" ,
690- available : true ,
724+ api : "google-generative-ai" ,
725+ baseUrl : "https://generativelanguage.googleapis.com/v1beta" ,
726+ input : [ "text" ] ,
727+ contextWindow : 1_000_000 ,
728+ maxTokens : 65_536 ,
729+ cost : { input : 0 , output : 0 , cacheRead : 0 , cacheWrite : 0 } ,
730+ } ;
731+ mocks . loadModelRegistry . mockResolvedValueOnce ( {
732+ models : [ googleModel ] ,
733+ availableKeys : new Set ( [ googleModelKey ] ) ,
734+ registry : { getAll : ( ) => [ googleModel ] } ,
691735 } ) ;
736+ const runtime = createRuntime ( ) ;
737+
738+ await modelsListCommand ( { all : true , json : true } , runtime as never ) ;
739+
740+ expectRowFields (
741+ lastPrintedRows < { key : string ; available : boolean } > ( ) ,
742+ googleModelKey ,
743+ { available : true } ,
744+ ) ;
745+ expect ( mocks . loadModelRegistry ) . toHaveBeenCalledOnce ( ) ;
746+
747+ mocks . loadStaticManifestCatalogRowsForList . mockReturnValueOnce ( [
748+ {
749+ ...googleModel ,
750+ ref : googleModelKey ,
751+ mergeKey : "google::gemini-3.1-flash-lite" ,
752+ source : "manifest" ,
753+ reasoning : false ,
754+ status : "available" ,
755+ } ,
756+ ] ) ;
757+
758+ await modelsListCommand ( { provider : "google" , json : true } , runtime as never ) ;
759+
760+ expectRowKeys ( lastPrintedRows < { key : string } > ( ) , [ googleModelKey ] ) ;
761+ expect ( mocks . loadModelRegistry ) . toHaveBeenCalledOnce ( ) ;
762+ expect ( mocks . loadModelCatalog ) . not . toHaveBeenCalled ( ) ;
692763 } ) ;
693764
694765 it ( "does not mark configured codex model as missing when forward-compat can build a fallback" , async ( ) => {
0 commit comments