@@ -20,31 +20,45 @@ import (
2020)
2121
2222func newListCmd () * cobra.Command {
23- var jsonFormat , openai , quiet bool
23+ var jsonFormat , quiet bool
24+ var openaiURL string
2425 c := & cobra.Command {
2526 Use : "list [OPTIONS] [MODEL]" ,
2627 Aliases : []string {"ls" },
2728 Short : "List the models pulled to your local environment" ,
2829 Args : cobra .MaximumNArgs (1 ),
2930 RunE : func (cmd * cobra.Command , args []string ) error {
30- if openai && quiet {
31- return fmt .Errorf ("--quiet flag cannot be used with --openai flag or OpenAI backend" )
31+ useOpenAI := openaiURL != ""
32+ if useOpenAI && quiet {
33+ return fmt .Errorf ("--quiet flag cannot be used with --openai flag" )
34+ }
35+
36+ var modelFilter string
37+ if len (args ) > 0 {
38+ modelFilter = args [0 ]
39+ }
40+
41+ // If --openai URL is provided, connect to external OpenAI endpoint
42+ if useOpenAI {
43+ openaiClient := desktop .NewOpenAIClient (openaiURL )
44+ models , err := listModelsFromOpenAI (openaiClient , modelFilter )
45+ if err != nil {
46+ return err
47+ }
48+ fmt .Fprint (cmd .OutOrStdout (), models )
49+ return nil
3250 }
3351
3452 // If we're doing an automatic install, only show the installation
3553 // status if it won't corrupt machine-readable output.
3654 var standaloneInstallPrinter standalone.StatusPrinter
37- if ! jsonFormat && ! openai && ! quiet {
55+ if ! jsonFormat && ! quiet {
3856 standaloneInstallPrinter = asPrinter (cmd )
3957 }
4058 if _ , err := ensureStandaloneRunnerAvailable (cmd .Context (), standaloneInstallPrinter , false ); err != nil {
4159 return fmt .Errorf ("unable to initialize standalone model runner: %w" , err )
4260 }
43- var modelFilter string
44- if len (args ) > 0 {
45- modelFilter = args [0 ]
46- }
47- models , err := listModels (openai , desktopClient , quiet , jsonFormat , modelFilter )
61+ models , err := listModels (desktopClient , quiet , jsonFormat , modelFilter )
4862 if err != nil {
4963 return err
5064 }
@@ -54,7 +68,7 @@ func newListCmd() *cobra.Command {
5468 ValidArgsFunction : completion .ModelNamesAndTags (getDesktopClient , 1 ),
5569 }
5670 c .Flags ().BoolVar (& jsonFormat , "json" , false , "List models in a JSON format" )
57- c .Flags ().BoolVar ( & openai , "openai" , false , "List models in an OpenAI format " )
71+ c .Flags ().StringVar ( & openaiURL , "openai" , "" , "List models from an OpenAI-compatible endpoint URL " )
5872 c .Flags ().BoolVarP (& quiet , "quiet" , "q" , false , "Only show model IDs" )
5973 return c
6074}
@@ -74,25 +88,58 @@ func matchesModelFilter(tag, filter string) bool {
7488 return repository == filter
7589}
7690
77- func listModels (openai bool , desktopClient * desktop.Client , quiet bool , jsonFormat bool , modelFilter string ) (string , error ) {
78- if openai {
79- models , err := desktopClient .ListOpenAI ()
80- if err != nil {
81- return "" , handleClientError (err , "Failed to list models" )
82- }
83- if modelFilter != "" {
84- filter := normalizeModelFilter (modelFilter )
85- filtered := models .Data [:0 ]
86- for _ , m := range models .Data {
87- if matchesModelFilter (m .ID , filter ) {
88- filtered = append (filtered , m )
89- }
91+ func listModelsFromOpenAI (openaiClient * desktop.OpenAIClient , modelFilter string ) (string , error ) {
92+ models , err := openaiClient .ListModels ()
93+ if err != nil {
94+ return "" , handleClientError (err , "Failed to list models" )
95+ }
96+ if modelFilter != "" {
97+ var filteredData []* dmrm.OpenAIModel
98+ for _ , m := range models .Data {
99+ if matchesModelFilter (m .ID , modelFilter ) {
100+ filteredData = append (filteredData , m )
90101 }
91- models .Data = filtered
92102 }
93- return formatter .ToStandardJSON (models )
103+ models .Data = filteredData
104+ }
105+ return prettyPrintOpenAIModels (models ), nil
106+ }
107+
108+ func prettyPrintOpenAIModels (models dmrm.OpenAIModelList ) string {
109+ // Sort models by ID
110+ sort .Slice (models .Data , func (i , j int ) bool {
111+ return strings .ToLower (models .Data [i ].ID ) < strings .ToLower (models .Data [j ].ID )
112+ })
113+
114+ var buf bytes.Buffer
115+ table := tablewriter .NewWriter (& buf )
116+
117+ table .SetHeader ([]string {"MODEL NAME" , "OWNED BY" })
118+
119+ table .SetBorder (false )
120+ table .SetColumnSeparator ("" )
121+ table .SetHeaderLine (false )
122+ table .SetTablePadding (" " )
123+ table .SetNoWhiteSpace (true )
124+
125+ table .SetColumnAlignment ([]int {
126+ tablewriter .ALIGN_LEFT , // MODEL NAME
127+ tablewriter .ALIGN_LEFT , // OWNED BY
128+ })
129+ table .SetHeaderAlignment (tablewriter .ALIGN_LEFT )
130+
131+ for _ , m := range models .Data {
132+ table .Append ([]string {
133+ m .ID ,
134+ m .OwnedBy ,
135+ })
94136 }
95137
138+ table .Render ()
139+ return buf .String ()
140+ }
141+
142+ func listModels (desktopClient * desktop.Client , quiet bool , jsonFormat bool , modelFilter string ) (string , error ) {
96143 models , err := desktopClient .List ()
97144 if err != nil {
98145 return "" , handleClientError (err , "Failed to list models" )
0 commit comments