1+ import { fetchAvailableModels } from "../../agent/model-list.js" ;
12import type { Command } from "../types.js" ;
23
34/**
@@ -37,15 +38,9 @@ export const modelCmd: Command = {
3738 handler : async ( args , ctx ) => {
3839 const arg = args . trim ( ) ;
3940 if ( ! arg ) {
40- // No-args opens the inline picker. For BYOK / non-proxy sessions
41- // there's no live model list to fetch, so print the static info
42- // instead of an empty overlay.
43- if ( ctx . bundle . source !== "proxy" ) {
44- const m = ctx . state . model ;
45- ctx . emit ( `Current model: ${ m . name } (${ m . provider } /${ m . id } )` ) ;
46- ctx . emit ( "BYOK session — switch via CODEBASE_PROVIDER + CODEBASE_MODEL env vars at launch." ) ;
47- return { handled : true } ;
48- }
41+ // No-args opens the inline picker — it fetches the live model list
42+ // from whatever this session talks to (proxy, an OpenAI-compatible /
43+ // local server, Anthropic, Google) and switches in place.
4944 ctx . openModelPicker ( ) ;
5045 return { handled : true } ;
5146 }
@@ -67,61 +62,38 @@ export const modelCmd: Command = {
6762export const modelsCmd : Command = {
6863 name : "models" ,
6964 aliases : [ "lm" ] ,
70- description : "List models available to your account (fetched live from the proxy)." ,
65+ description : "List the models this session can switch to ( live from the proxy, provider API, or local server )." ,
7166 handler : async ( _args , ctx ) => {
72- // BYOK users don't go through our proxy — there's no central
73- // "available models" endpoint for arbitrary upstreams. Tell them
74- // how to switch and bail.
75- if ( ctx . bundle . source !== "proxy" ) {
67+ const apiKey = await ctx . bundle . agent . getApiKey ?.( ctx . bundle . model . provider ) ;
68+ let models : Array < { id : string ; name : string ; provider : string } > ;
69+ try {
70+ models = await fetchAvailableModels ( ctx . bundle . model , apiKey ) ;
71+ } catch ( err ) {
72+ ctx . emit ( `(couldn't list models: ${ err instanceof Error ? err . message : String ( err ) } )` ) ;
7673 ctx . emit ( `Current: ${ ctx . state . model . name } (${ ctx . state . model . provider } /${ ctx . state . model . id } )` ) ;
77- ctx . emit ( "BYOK session — switch by re-launching with CODEBASE_PROVIDER + CODEBASE_MODEL env vars." ) ;
7874 return { handled : true } ;
7975 }
80- const baseUrl = ( ctx . bundle . model . baseUrl ?? "" ) . replace ( / \/ + $ / , "" ) ;
81- if ( ! baseUrl ) {
82- ctx . emit ( "(model has no baseUrl — can't query the proxy)" ) ;
76+ if ( models . length === 0 ) {
77+ ctx . emit ( `(no models returned for ${ ctx . bundle . model . provider } )` ) ;
8378 return { handled : true } ;
8479 }
85- try {
86- const apiKey = await ctx . bundle . agent . getApiKey ?.( ctx . bundle . model . provider ) ;
87- if ( ! apiKey ) {
88- ctx . emit ( "(not signed in — run `codebase auth login`)" ) ;
89- return { handled : true } ;
90- }
91- const res = await fetch ( `${ baseUrl } /models` , {
92- headers : { Authorization : `Bearer ${ apiKey } ` , Accept : "application/json" } ,
93- } ) ;
94- if ( ! res . ok ) {
95- ctx . emit ( `(failed to fetch models: ${ res . status } ${ res . statusText } )` ) ;
96- return { handled : true } ;
97- }
98- const json = ( await res . json ( ) ) as { models ?: Array < { id : string ; name : string ; provider : string } > } ;
99- const models = json . models ?? [ ] ;
100- if ( models . length === 0 ) {
101- ctx . emit ( "(no models returned)" ) ;
102- return { handled : true } ;
103- }
104- const current = `${ ctx . state . model . provider } /${ ctx . state . model . id } ` ;
105- ctx . emit ( "Available models (* = active):" ) ;
106- // Group by provider so the list reads as a tree.
107- const byProvider = new Map < string , Array < { id : string ; name : string } > > ( ) ;
108- for ( const m of models ) {
109- const arr = byProvider . get ( m . provider ) ?? [ ] ;
110- arr . push ( { id : m . id , name : m . name } ) ;
111- byProvider . set ( m . provider , arr ) ;
112- }
113- const providers = [ ...byProvider . keys ( ) ] . sort ( ) ;
114- for ( const p of providers ) {
115- ctx . emit ( ` ${ p } :` ) ;
116- for ( const m of byProvider . get ( p ) ?? [ ] ) {
117- const marker = `${ p } /${ m . id } ` === current ? "*" : " " ;
118- ctx . emit ( ` ${ marker } ${ m . id } ${ m . name === m . id ? "" : `· ${ m . name } ` } ` ) ;
119- }
80+ const current = `${ ctx . state . model . provider } /${ ctx . state . model . id } ` ;
81+ ctx . emit ( "Available models (* = active):" ) ;
82+ // Group by provider so the list reads as a tree.
83+ const byProvider = new Map < string , Array < { id : string ; name : string } > > ( ) ;
84+ for ( const m of models ) {
85+ const arr = byProvider . get ( m . provider ) ?? [ ] ;
86+ arr . push ( { id : m . id , name : m . name } ) ;
87+ byProvider . set ( m . provider , arr ) ;
88+ }
89+ for ( const p of [ ...byProvider . keys ( ) ] . sort ( ) ) {
90+ ctx . emit ( ` ${ p } :` ) ;
91+ for ( const m of byProvider . get ( p ) ?? [ ] ) {
92+ const marker = `${ p } /${ m . id } ` === current || m . id === ctx . state . model . id ? "*" : " " ;
93+ ctx . emit ( ` ${ marker } ${ m . id } ${ m . name === m . id ? "" : ` · ${ m . name } ` } ` ) ;
12094 }
121- ctx . emit ( "Switch: /model <id> · /model <provider>:<id>" ) ;
122- } catch ( err ) {
123- ctx . emit ( `(error fetching models: ${ err instanceof Error ? err . message : String ( err ) } )` ) ;
12495 }
96+ ctx . emit ( "Switch: /model <id> · /model <provider>:<id> · or /model for the picker" ) ;
12597 return { handled : true } ;
12698 } ,
12799} ;
0 commit comments