@@ -123,6 +123,21 @@ const buildModelListResponse = (models, fallbackModel) => {
123123 return { object : 'list' , data } ;
124124} ;
125125
126+ const normalizeModelIds = ( models ) => {
127+ if ( ! Array . isArray ( models ) ) return [ ] ;
128+ return models . map ( ( model ) => {
129+ if ( typeof model === 'string' ) return model ;
130+ if ( model && model . id ) return model . id ;
131+ return null ;
132+ } ) . filter ( Boolean ) ;
133+ } ;
134+
135+ const resolveAvailableModelsRaw = async ( puter ) => {
136+ if ( ! puter . ai || typeof puter . ai . listModels !== 'function' ) return [ ] ;
137+ const models = await puter . ai . listModels ( ) ;
138+ return Array . isArray ( models ) ? models : [ ] ;
139+ } ;
140+
126141export const createAIProxyServer = ( options = { } ) => {
127142 const defaults = {
128143 host : options . host || '127.0.0.1' ,
@@ -132,11 +147,18 @@ export const createAIProxyServer = (options = {}) => {
132147 maxTokens : normalizeNumber ( options . maxTokens , 1024 ) ,
133148 temperature : normalizeNumber ( options . temperature , 1 )
134149 } ;
150+ const availableModelsRaw = options . availableModelsRaw ;
151+ const availableModelsNormalized = Array . isArray ( availableModelsRaw )
152+ ? normalizeModelIds ( availableModelsRaw )
153+ : null ;
135154
136155 const modelsHandler = async ( { res } ) => {
137156 try {
157+ if ( Array . isArray ( availableModelsRaw ) ) {
158+ return sendJson ( res , 200 , buildModelListResponse ( availableModelsRaw , defaults . model ) ) ;
159+ }
138160 const puter = getPuter ( ) ;
139- const models = typeof puter . ai ?. listModels === 'function' ? await puter . ai . listModels ( ) : [ ] ;
161+ const models = await resolveAvailableModelsRaw ( puter ) ;
140162 return sendJson ( res , 200 , buildModelListResponse ( models , defaults . model ) ) ;
141163 } catch ( error ) {
142164 return sendJson ( res , 500 , { error : { message : error . message || 'Failed to list models' } } ) ;
@@ -148,7 +170,7 @@ export const createAIProxyServer = (options = {}) => {
148170 method : 'GET' ,
149171 path : '/' ,
150172 handler : async ( { res } ) => {
151- return sendJson ( res , 200 , { status : 'ok' , message : 'Puter AI proxy running on /v1' } ) ;
173+ return sendJson ( res , 200 , { status : 'ok' , message : 'Puter AI running on /v1' } ) ;
152174 }
153175 } ,
154176 {
@@ -192,6 +214,17 @@ export const createAIProxyServer = (options = {}) => {
192214 return sendJson ( res , 500 , { error : { message : 'AI service not available' , type : 'service_unavailable' } } ) ;
193215 }
194216
217+ if ( availableModelsNormalized ) {
218+ if ( availableModelsNormalized . length > 0 && ! availableModelsNormalized . includes ( model ) ) {
219+ return sendJson ( res , 400 , { error : { message : `Unknown model: ${ model } ` , type : 'invalid_request_error' } } ) ;
220+ }
221+ } else if ( typeof puter . ai . listModels === 'function' ) {
222+ const availableModels = normalizeModelIds ( await puter . ai . listModels ( ) ) ;
223+ if ( availableModels . length > 0 && ! availableModels . includes ( model ) ) {
224+ return sendJson ( res , 400 , { error : { message : `Unknown model: ${ model } ` , type : 'invalid_request_error' } } ) ;
225+ }
226+ }
227+
195228 const result = await puter . ai . chat ( prompt , {
196229 model,
197230 temperature,
@@ -224,15 +257,48 @@ export const createAIProxyServer = (options = {}) => {
224257} ;
225258
226259export const startAIProxyServer = async ( options = { } ) => {
260+ const requestedModel = typeof options . model === 'string'
261+ ? options . model . trim ( )
262+ : ( options . model ? String ( options . model ) . trim ( ) : '' ) ;
227263 const defaults = {
228264 host : options . host || '127.0.0.1' ,
229265 port : normalizeNumber ( options . port , 8080 ) ,
230- model : options . model || process . env . PUTER_AI_MODEL || 'gpt-5-nano' ,
266+ model : requestedModel || process . env . PUTER_AI_MODEL || 'gpt-5-nano' ,
231267 system : options . system ?? process . env . PUTER_AI_SYSTEM ?? '' ,
232268 maxTokens : normalizeNumber ( options . maxTokens , 1024 ) ,
233269 temperature : normalizeNumber ( options . temperature , 1 )
234270 } ;
235- const server = createAIProxyServer ( defaults ) ;
271+ const profileModule = getProfileModule ( ) ;
272+ const authToken = profileModule . getAuthToken ( ) ;
273+ if ( ! authToken ) {
274+ throw new Error ( 'Not authenticated. Run: puter login' ) ;
275+ }
276+
277+ const puter = getPuter ( ) ;
278+ const availableModelsRaw = await resolveAvailableModelsRaw ( puter ) ;
279+ const availableModels = normalizeModelIds ( availableModelsRaw ) ;
280+ if ( requestedModel && availableModels . length > 0 && ! availableModels . includes ( requestedModel ) ) {
281+ console . error ( chalk . red ( `Unknown model: ${ requestedModel } ` ) ) ;
282+ const normalizedQuery = requestedModel . toLowerCase ( ) ;
283+ const tokens = normalizedQuery . split ( / [ - _ / ] / ) . filter ( Boolean ) ;
284+ const primaryToken = tokens [ 0 ] ;
285+ const prefix = normalizedQuery . slice ( 0 , 3 ) ;
286+ const suggestedModels = Array . from ( new Set ( availableModels . filter ( ( model ) => {
287+ const lower = model . toLowerCase ( ) ;
288+ if ( primaryToken && lower . includes ( primaryToken ) ) return true ;
289+ if ( ! primaryToken && normalizedQuery . length > 3 && lower . includes ( prefix ) ) return true ;
290+ return false ;
291+ } ) ) ) ;
292+ if ( suggestedModels . length > 0 ) {
293+ console . log ( chalk . cyan ( 'Try one of the following:' ) ) ;
294+ for ( const suggestedModel of suggestedModels ) {
295+ console . log ( chalk . dim ( ` ${ suggestedModel } ` ) ) ;
296+ }
297+ }
298+ return null ;
299+ }
300+
301+ const server = createAIProxyServer ( { ...defaults , availableModelsRaw } ) ;
236302 const { host, port } = await server . start ( ) ;
237303 const trimmedSystem = String ( defaults . system || '' ) . trim ( ) ;
238304 const systemPreview = trimmedSystem
0 commit comments