refactor: improve error response for non-available models (#298)
This commit is contained in:
committed by
GitHub
parent
694c242865
commit
2031c67d46
42
scripts/system-check.test.ts
Normal file
42
scripts/system-check.test.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import { describe, expect, test } from 'bun:test'
|
||||||
|
|
||||||
|
import { formatReachabilityFailureDetail } from './system-check.ts'
|
||||||
|
|
||||||
|
describe('formatReachabilityFailureDetail', () => {
|
||||||
|
test('returns generic failure detail for non-codex transport', () => {
|
||||||
|
const detail = formatReachabilityFailureDetail(
|
||||||
|
'https://api.openai.com/v1/models',
|
||||||
|
429,
|
||||||
|
'{"error":"rate_limit"}',
|
||||||
|
{
|
||||||
|
transport: 'chat_completions',
|
||||||
|
requestedModel: 'gpt-4o',
|
||||||
|
resolvedModel: 'gpt-4o',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(detail).toBe(
|
||||||
|
'Unexpected status 429 from https://api.openai.com/v1/models. Body: {"error":"rate_limit"}',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('adds alias/entitlement hint for codex model support 400s', () => {
|
||||||
|
const detail = formatReachabilityFailureDetail(
|
||||||
|
'https://chatgpt.com/backend-api/codex/responses',
|
||||||
|
400,
|
||||||
|
'{"detail":"The \\"gpt-5.3-codex-spark\\" model is not supported when using Codex with a ChatGPT account."}',
|
||||||
|
{
|
||||||
|
transport: 'codex_responses',
|
||||||
|
requestedModel: 'codexspark',
|
||||||
|
resolvedModel: 'gpt-5.3-codex-spark',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(detail).toContain(
|
||||||
|
'model alias "codexspark" resolved to "gpt-5.3-codex-spark"',
|
||||||
|
)
|
||||||
|
expect(detail).toContain(
|
||||||
|
'Try "codexplan" or another entitled Codex model.',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -58,6 +58,31 @@ function parseOptions(argv: string[]): CliOptions {
|
|||||||
return options
|
return options
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function formatReachabilityFailureDetail(
|
||||||
|
endpoint: string,
|
||||||
|
status: number,
|
||||||
|
responseBody: string,
|
||||||
|
request: {
|
||||||
|
transport: string
|
||||||
|
requestedModel: string
|
||||||
|
resolvedModel: string
|
||||||
|
},
|
||||||
|
): string {
|
||||||
|
const compactBody = responseBody.trim().replace(/\s+/g, ' ').slice(0, 240)
|
||||||
|
const base = `Unexpected status ${status} from ${endpoint}.`
|
||||||
|
const bodySuffix = compactBody ? ` Body: ${compactBody}` : ''
|
||||||
|
|
||||||
|
if (request.transport !== 'codex_responses' || status !== 400) {
|
||||||
|
return `${base}${bodySuffix}`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!/not supported.*chatgpt account/i.test(responseBody)) {
|
||||||
|
return `${base}${bodySuffix}`
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${base}${bodySuffix} Hint: model alias "${request.requestedModel}" resolved to "${request.resolvedModel}", which this ChatGPT account does not currently allow. Try "codexplan" or another entitled Codex model.`
|
||||||
|
}
|
||||||
|
|
||||||
function checkNodeVersion(): CheckResult {
|
function checkNodeVersion(): CheckResult {
|
||||||
const raw = process.versions.node
|
const raw = process.versions.node
|
||||||
const major = Number(raw.split('.')[0] ?? '0')
|
const major = Number(raw.split('.')[0] ?? '0')
|
||||||
@@ -284,6 +309,7 @@ async function checkBaseUrlReachability(): Promise<CheckResult> {
|
|||||||
headers['chatgpt-account-id'] = credentials.accountId
|
headers['chatgpt-account-id'] = credentials.accountId
|
||||||
}
|
}
|
||||||
headers['Content-Type'] = 'application/json'
|
headers['Content-Type'] = 'application/json'
|
||||||
|
headers.originator = 'openclaude'
|
||||||
method = 'POST'
|
method = 'POST'
|
||||||
body = JSON.stringify({
|
body = JSON.stringify({
|
||||||
model: request.resolvedModel,
|
model: request.resolvedModel,
|
||||||
@@ -315,7 +341,17 @@ async function checkBaseUrlReachability(): Promise<CheckResult> {
|
|||||||
return pass('Provider reachability', `Reached ${endpoint} (status ${response.status}).`)
|
return pass('Provider reachability', `Reached ${endpoint} (status ${response.status}).`)
|
||||||
}
|
}
|
||||||
|
|
||||||
return fail('Provider reachability', `Unexpected status ${response.status} from ${endpoint}.`)
|
const responseBody = await response.text().catch(() => '')
|
||||||
|
const detail = formatReachabilityFailureDetail(
|
||||||
|
endpoint,
|
||||||
|
response.status,
|
||||||
|
responseBody,
|
||||||
|
request,
|
||||||
|
)
|
||||||
|
return fail(
|
||||||
|
'Provider reachability',
|
||||||
|
detail,
|
||||||
|
)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const message = error instanceof Error ? error.message : String(error)
|
const message = error instanceof Error ? error.message : String(error)
|
||||||
return fail('Provider reachability', `Failed to reach ${endpoint}: ${message}`)
|
return fail('Provider reachability', `Failed to reach ${endpoint}: ${message}`)
|
||||||
@@ -504,6 +540,8 @@ async function main(): Promise<void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await main()
|
if (import.meta.main) {
|
||||||
|
await main()
|
||||||
|
}
|
||||||
|
|
||||||
export {}
|
export {}
|
||||||
|
|||||||
Reference in New Issue
Block a user