Handle Z.AI textual 401 errors for auth diagnostics
This commit is contained in:
@@ -47,14 +47,14 @@
|
||||
"status": "completed",
|
||||
"date": "2026-02-16",
|
||||
"updated": "2026-02-16",
|
||||
"summary": "Unified Z.AI credential resolution so zhipuai model switches resolve credentials from config, env (including ZAI_API_KEY), and auth store regardless of use_oauth flag. Added clearer Z.AI-specific 401 diagnostics when API auth fails (including missing model.request scope hint).",
|
||||
"summary": "Unified Z.AI credential resolution so zhipuai model switches resolve credentials from config, env (including ZAI_API_KEY), and auth store regardless of use_oauth flag. Added clearer Z.AI-specific 401 diagnostics when API auth fails (including missing model.request scope hint), including textual 401 errors where the SDK does not expose status.",
|
||||
"files_modified": [
|
||||
"src/daemon/models.ts",
|
||||
"src/models/openai.ts",
|
||||
"src/daemon/clientFactory.test.ts",
|
||||
"src/models/openai.test.ts"
|
||||
],
|
||||
"test_status": "pnpm test:run src/daemon/clientFactory.test.ts src/models/openai.test.ts + pnpm typecheck passing"
|
||||
"test_status": "pnpm test:run src/daemon/clientFactory.test.ts src/models/openai.test.ts + pnpm typecheck passing (updated to cover textual 401 without status field)"
|
||||
},
|
||||
|
||||
"deployment-port-env-override": {
|
||||
|
||||
@@ -152,4 +152,20 @@ describe('OpenAIClient tool use', () => {
|
||||
messages: [{ role: 'user', content: 'hello' }],
|
||||
})).rejects.toThrow(/Z\.AI authentication failed \(401\)/);
|
||||
});
|
||||
|
||||
it('rewrites Z.AI textual 401 errors when SDK status is absent', async () => {
|
||||
mockCreate.mockRejectedValueOnce(new Error(
|
||||
'401 You have insufficient permissions for this operation. Missing scopes: model.request.',
|
||||
));
|
||||
|
||||
const client = new OpenAIClient({
|
||||
apiKey: 'zai-key',
|
||||
model: 'glm-4.7',
|
||||
baseURL: 'https://api.z.ai/api/paas/v4',
|
||||
});
|
||||
|
||||
await expect(client.chat({
|
||||
messages: [{ role: 'user', content: 'hello' }],
|
||||
})).rejects.toThrow(/The key lacks `model\.request` scope/);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -260,9 +260,10 @@ export class OpenAIClient implements ModelClient {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
|
||||
const isZai = (this.baseURL ?? '').includes('api.z.ai');
|
||||
const isUnauthorized401 = status === 401 || /\b401\b/.test(message);
|
||||
const missingModelRequestScope = message.includes('Missing scopes: model.request');
|
||||
|
||||
if (isZai && status === 401) {
|
||||
if (isZai && isUnauthorized401) {
|
||||
const hint = missingModelRequestScope
|
||||
? 'The key lacks `model.request` scope.'
|
||||
: 'The API key is invalid, expired, or not allowed for this model/endpoint.';
|
||||
|
||||
Reference in New Issue
Block a user