@@ -12,13 +12,17 @@ process.chdir(pkgDir)
1212
1313type Args = {
1414 providerIDs : string [ ]
15+ modelIDs : string [ ]
16+ scope : "all" | "gpt5-plus"
1517 timeoutMs : number
1618 delayMs : number
1719 limit : number | undefined
1820}
1921
2022function parseArgs ( argv : string [ ] ) : Args {
2123 const providerIDs : string [ ] = [ ]
24+ const modelIDs : string [ ] = [ ]
25+ let scope : Args [ "scope" ] = "all"
2226 let timeoutMs = 20_000
2327 let delayMs = 250
2428 let limit : number | undefined
@@ -33,6 +37,22 @@ function parseArgs(argv: string[]): Args {
3337 providerIDs . push ( value )
3438 break
3539 }
40+ case "--model" :
41+ case "-m" : {
42+ const value = argv [ ++ i ]
43+ if ( ! value ) throw new Error ( "Missing value for --model" )
44+ modelIDs . push ( value )
45+ break
46+ }
47+ case "--scope" : {
48+ const value = argv [ ++ i ]
49+ if ( ! value ) throw new Error ( "Missing value for --scope" )
50+ if ( value !== "all" && value !== "gpt5-plus" ) {
51+ throw new Error ( '--scope must be one of: all, gpt5-plus' )
52+ }
53+ scope = value
54+ break
55+ }
3656 case "--timeout-ms" : {
3757 const value = argv [ ++ i ]
3858 if ( ! value ) throw new Error ( "Missing value for --timeout-ms" )
@@ -71,7 +91,7 @@ function parseArgs(argv: string[]): Args {
7191 if ( ! Number . isFinite ( delayMs ) || delayMs < 0 ) throw new Error ( "--delay-ms must be >= 0" )
7292 if ( limit !== undefined && ( ! Number . isFinite ( limit ) || limit <= 0 ) ) throw new Error ( "--limit must be > 0" )
7393
74- return { providerIDs, timeoutMs, delayMs, limit }
94+ return { providerIDs, modelIDs , scope , timeoutMs, delayMs, limit }
7595}
7696
7797function printHelp ( ) {
@@ -87,6 +107,8 @@ function printHelp() {
87107 "" ,
88108 "Options:" ,
89109 " -p, --provider <id> Provider ID to test (repeatable). Default: github-copilot" ,
110+ " -m, --model <id> Model ID to test (repeatable). If set, only probes these models." ,
111+ " --scope <mode> Model selection mode when --model is not set: all | gpt5-plus (default: all)" ,
90112 " --timeout-ms <n> Per-model timeout (default: 20000)" ,
91113 " --delay-ms <n> Delay between models (default: 250)" ,
92114 " --limit <n> Only test the first N models per provider" ,
@@ -117,6 +139,41 @@ function matchesExtraModelID(modelID: string): boolean {
117139 return extra . some ( ( base ) => modelID === base || modelID . startsWith ( `${ base } -` ) )
118140}
119141
142+ function selectModelIDs ( input : {
143+ availableModelIDs : string [ ]
144+ requestedModelIDs : string [ ]
145+ scope : Args [ "scope" ]
146+ limit : number | undefined
147+ } ) : string [ ] {
148+ const gptAvailableModelIDs = input . availableModelIDs . filter ( ( id ) => / g p t / i. test ( id ) )
149+ const available = new Set ( gptAvailableModelIDs )
150+
151+ let selected : string [ ]
152+ if ( input . requestedModelIDs . length > 0 ) {
153+ const nonGpt = input . requestedModelIDs . filter ( ( id ) => ! / g p t / i. test ( id ) )
154+ if ( nonGpt . length > 0 ) {
155+ process . stdout . write ( `\n(Note) Skipping non-GPT model(s): ${ nonGpt . join ( ", " ) } \n` )
156+ }
157+ selected = input . requestedModelIDs . filter ( ( id ) => / g p t / i. test ( id ) && available . has ( id ) )
158+ const missing = input . requestedModelIDs . filter ( ( id ) => / g p t / i. test ( id ) && ! available . has ( id ) )
159+ if ( missing . length > 0 ) {
160+ process . stdout . write ( `\n(Note) Skipping unknown model(s): ${ missing . join ( ", " ) } \n` )
161+ }
162+ } else if ( input . scope === "gpt5-plus" ) {
163+ selected = gptAvailableModelIDs
164+ . filter ( ( id ) => {
165+ const major = getGptMajor ( id )
166+ if ( major !== undefined && major >= 5 ) return true
167+ return matchesExtraModelID ( id )
168+ } )
169+ . sort ( ( a , b ) => a . localeCompare ( b ) )
170+ } else {
171+ selected = [ ...gptAvailableModelIDs ] . sort ( ( a , b ) => a . localeCompare ( b ) )
172+ }
173+
174+ return input . limit ? selected . slice ( 0 , input . limit ) : selected
175+ }
176+
120177type ApiRoute = "responses" | "chat" | "unknown"
121178
122179function inferApiRoute ( urls : string [ ] ) : ApiRoute {
@@ -221,16 +278,16 @@ async function probeModel(input: {
221278 abortSignal : AbortSignal . timeout ( input . timeoutMs ) ,
222279 } )
223280
224- activeProbeKey = undefined
225281 const urls = requestLog . get ( key ) ?? [ ]
226282 return { ok : true , api : inferApiRoute ( urls ) }
227283 } catch ( e : any ) {
228284 const key = `${ input . providerID } /${ input . modelID } `
229- activeProbeKey = undefined
230285 const urls = requestLog . get ( key ) ?? [ ]
231286 const api = inferApiRoute ( urls )
232287 const message = e ?. message ? String ( e . message ) : String ( e )
233288 return { ok : false , api, error : message }
289+ } finally {
290+ activeProbeKey = undefined
234291 }
235292}
236293
@@ -245,6 +302,11 @@ async function main() {
245302
246303 process . stdout . write ( "# Copilot Responses API Probe\n" )
247304 process . stdout . write ( `Providers: ${ args . providerIDs . join ( ", " ) } \n` )
305+ process . stdout . write (
306+ args . modelIDs . length > 0
307+ ? `Models: ${ args . modelIDs . join ( ", " ) } \n`
308+ : `Scope: ${ args . scope } \n` ,
309+ )
248310 process . stdout . write ( `Timeout: ${ args . timeoutMs } ms, Delay: ${ args . delayMs } ms\n\n` )
249311
250312 let hadFailure = false
@@ -259,15 +321,13 @@ async function main() {
259321 continue
260322 }
261323
262- const modelIDs = Object . keys ( provider . models )
263- . filter ( ( id ) => {
264- const major = getGptMajor ( id )
265- if ( major !== undefined && major >= 5 ) return true
266- return matchesExtraModelID ( id )
267- } )
268- . sort ( ( a , b ) => a . localeCompare ( b ) )
269-
270- const selected = args . limit ? modelIDs . slice ( 0 , args . limit ) : modelIDs
324+ const availableModelIDs = Object . keys ( provider . models )
325+ const selected = selectModelIDs ( {
326+ availableModelIDs,
327+ requestedModelIDs : args . modelIDs ,
328+ scope : args . scope ,
329+ limit : args . limit ,
330+ } )
271331
272332 process . stdout . write ( `\n## ${ providerID } \n` )
273333 process . stdout . write ( `Testing ${ selected . length } model(s)\n` )
0 commit comments