diff options
Diffstat (limited to 'packages/cli/src/ui/utils/errorParsing.test.ts')
| -rw-r--r-- | packages/cli/src/ui/utils/errorParsing.test.ts | 309 |
1 files changed, 304 insertions, 5 deletions
diff --git a/packages/cli/src/ui/utils/errorParsing.test.ts b/packages/cli/src/ui/utils/errorParsing.test.ts index 4bbaabf1..3d228efb 100644 --- a/packages/cli/src/ui/utils/errorParsing.test.ts +++ b/packages/cli/src/ui/utils/errorParsing.test.ts @@ -6,10 +6,16 @@ import { describe, it, expect } from 'vitest'; import { parseAndFormatApiError } from './errorParsing.js'; -import { AuthType, StructuredError } from '@google/gemini-cli-core'; +import { + AuthType, + UserTierId, + DEFAULT_GEMINI_FLASH_MODEL, + isProQuotaExceededError, +} from '@google/gemini-cli-core'; describe('parseAndFormatApiError', () => { - const enterpriseMessage = 'upgrade to a plan with higher limits'; + const _enterpriseMessage = + 'upgrade to a Gemini Code Assist Standard or Enterprise plan with higher limits'; const vertexMessage = 'request a quota increase through Vertex'; const geminiMessage = 'request a quota increase through AI Studio'; @@ -24,9 +30,17 @@ describe('parseAndFormatApiError', () => { it('should format a 429 API error with the default message', () => { const errorMessage = 'got status: 429 Too Many Requests. {"error":{"code":429,"message":"Rate limit exceeded","status":"RESOURCE_EXHAUSTED"}}'; - const result = parseAndFormatApiError(errorMessage); + const result = parseAndFormatApiError( + errorMessage, + undefined, + undefined, + 'gemini-2.5-pro', + DEFAULT_GEMINI_FLASH_MODEL, + ); expect(result).toContain('[API Error: Rate limit exceeded'); - expect(result).toContain('Your request has been rate limited'); + expect(result).toContain( + 'Slow response times detected. Switching to the gemini-2.5-flash model', + ); }); it('should format a 429 API error with the personal message', () => { @@ -35,9 +49,14 @@ describe('parseAndFormatApiError', () => { const result = parseAndFormatApiError( errorMessage, AuthType.LOGIN_WITH_GOOGLE, + undefined, + 'gemini-2.5-pro', + DEFAULT_GEMINI_FLASH_MODEL, ); expect(result).toContain('[API Error: Rate limit exceeded'); - expect(result).toContain(enterpriseMessage); + expect(result).toContain( + 'Slow response times detected. Switching to the gemini-2.5-flash model', + ); }); it('should format a 429 API error with the vertex message', () => { @@ -116,4 +135,284 @@ describe('parseAndFormatApiError', () => { const expected = '[API Error: An unknown error occurred.]'; expect(parseAndFormatApiError(error)).toBe(expected); }); + + it('should format a 429 API error with Pro quota exceeded message for Google auth (Free tier)', () => { + const errorMessage = + 'got status: 429 Too Many Requests. {"error":{"code":429,"message":"Quota exceeded for quota metric \'Gemini 2.5 Pro Requests\' and limit \'RequestsPerDay\' of service \'generativelanguage.googleapis.com\' for consumer \'project_number:123456789\'.","status":"RESOURCE_EXHAUSTED"}}'; + const result = parseAndFormatApiError( + errorMessage, + AuthType.LOGIN_WITH_GOOGLE, + undefined, + 'gemini-2.5-pro', + DEFAULT_GEMINI_FLASH_MODEL, + ); + expect(result).toContain( + "[API Error: Quota exceeded for quota metric 'Gemini 2.5 Pro Requests'", + ); + expect(result).toContain( + 'You have reached your daily gemini-2.5-pro quota limit', + ); + expect(result).toContain( + 'upgrade to a Gemini Code Assist Standard or Enterprise plan', + ); + }); + + it('should format a regular 429 API error with standard message for Google auth', () => { + const errorMessage = + 'got status: 429 Too Many Requests. {"error":{"code":429,"message":"Rate limit exceeded","status":"RESOURCE_EXHAUSTED"}}'; + const result = parseAndFormatApiError( + errorMessage, + AuthType.LOGIN_WITH_GOOGLE, + undefined, + 'gemini-2.5-pro', + DEFAULT_GEMINI_FLASH_MODEL, + ); + expect(result).toContain('[API Error: Rate limit exceeded'); + expect(result).toContain( + 'Slow response times detected. Switching to the gemini-2.5-flash model', + ); + expect(result).not.toContain( + 'You have reached your daily gemini-2.5-pro quota limit', + ); + }); + + it('should format a 429 API error with generic quota exceeded message for Google auth', () => { + const errorMessage = + 'got status: 429 Too Many Requests. {"error":{"code":429,"message":"Quota exceeded for quota metric \'GenerationRequests\' and limit \'RequestsPerDay\' of service \'generativelanguage.googleapis.com\' for consumer \'project_number:123456789\'.","status":"RESOURCE_EXHAUSTED"}}'; + const result = parseAndFormatApiError( + errorMessage, + AuthType.LOGIN_WITH_GOOGLE, + undefined, + 'gemini-2.5-pro', + DEFAULT_GEMINI_FLASH_MODEL, + ); + expect(result).toContain( + "[API Error: Quota exceeded for quota metric 'GenerationRequests'", + ); + expect(result).toContain('You have reached your daily quota limit'); + expect(result).not.toContain( + 'You have reached your daily Gemini 2.5 Pro quota limit', + ); + }); + + it('should prioritize Pro quota message over generic quota message for Google auth', () => { + const errorMessage = + 'got status: 429 Too Many Requests. {"error":{"code":429,"message":"Quota exceeded for quota metric \'Gemini 2.5 Pro Requests\' and limit \'RequestsPerDay\' of service \'generativelanguage.googleapis.com\' for consumer \'project_number:123456789\'.","status":"RESOURCE_EXHAUSTED"}}'; + const result = parseAndFormatApiError( + errorMessage, + AuthType.LOGIN_WITH_GOOGLE, + undefined, + 'gemini-2.5-pro', + DEFAULT_GEMINI_FLASH_MODEL, + ); + expect(result).toContain( + "[API Error: Quota exceeded for quota metric 'Gemini 2.5 Pro Requests'", + ); + expect(result).toContain( + 'You have reached your daily gemini-2.5-pro quota limit', + ); + expect(result).not.toContain('You have reached your daily quota limit'); + }); + + it('should format a 429 API error with Pro quota exceeded message for Google auth (Standard tier)', () => { + const errorMessage = + 'got status: 429 Too Many Requests. {"error":{"code":429,"message":"Quota exceeded for quota metric \'Gemini 2.5 Pro Requests\' and limit \'RequestsPerDay\' of service \'generativelanguage.googleapis.com\' for consumer \'project_number:123456789\'.","status":"RESOURCE_EXHAUSTED"}}'; + const result = parseAndFormatApiError( + errorMessage, + AuthType.LOGIN_WITH_GOOGLE, + UserTierId.STANDARD, + 'gemini-2.5-pro', + DEFAULT_GEMINI_FLASH_MODEL, + ); + expect(result).toContain( + "[API Error: Quota exceeded for quota metric 'Gemini 2.5 Pro Requests'", + ); + expect(result).toContain( + 'You have reached your daily gemini-2.5-pro quota limit', + ); + expect(result).toContain( + 'We appreciate you for choosing Gemini Code Assist and the Gemini CLI', + ); + expect(result).not.toContain( + 'upgrade to a Gemini Code Assist Standard or Enterprise plan', + ); + }); + + it('should format a 429 API error with Pro quota exceeded message for Google auth (Legacy tier)', () => { + const errorMessage = + 'got status: 429 Too Many Requests. {"error":{"code":429,"message":"Quota exceeded for quota metric \'Gemini 2.5 Pro Requests\' and limit \'RequestsPerDay\' of service \'generativelanguage.googleapis.com\' for consumer \'project_number:123456789\'.","status":"RESOURCE_EXHAUSTED"}}'; + const result = parseAndFormatApiError( + errorMessage, + AuthType.LOGIN_WITH_GOOGLE, + UserTierId.LEGACY, + 'gemini-2.5-pro', + DEFAULT_GEMINI_FLASH_MODEL, + ); + expect(result).toContain( + "[API Error: Quota exceeded for quota metric 'Gemini 2.5 Pro Requests'", + ); + expect(result).toContain( + 'You have reached your daily gemini-2.5-pro quota limit', + ); + expect(result).toContain( + 'We appreciate you for choosing Gemini Code Assist and the Gemini CLI', + ); + expect(result).not.toContain( + 'upgrade to a Gemini Code Assist Standard or Enterprise plan', + ); + }); + + it('should handle different Gemini version strings in Pro quota exceeded errors', () => { + const errorMessage15 = + 'got status: 429 Too Many Requests. {"error":{"code":429,"message":"Quota exceeded for quota metric \'Gemini 1.5 Pro Requests\' and limit \'RequestsPerDay\' of service \'generativelanguage.googleapis.com\' for consumer \'project_number:123456789\'.","status":"RESOURCE_EXHAUSTED"}}'; + const errorMessagePreview = + 'got status: 429 Too Many Requests. {"error":{"code":429,"message":"Quota exceeded for quota metric \'Gemini 2.5-preview Pro Requests\' and limit \'RequestsPerDay\' of service \'generativelanguage.googleapis.com\' for consumer \'project_number:123456789\'.","status":"RESOURCE_EXHAUSTED"}}'; + const errorMessageBeta = + 'got status: 429 Too Many Requests. {"error":{"code":429,"message":"Quota exceeded for quota metric \'Gemini beta-3.0 Pro Requests\' and limit \'RequestsPerDay\' of service \'generativelanguage.googleapis.com\' for consumer \'project_number:123456789\'.","status":"RESOURCE_EXHAUSTED"}}'; + const errorMessageExperimental = + 'got status: 429 Too Many Requests. {"error":{"code":429,"message":"Quota exceeded for quota metric \'Gemini experimental-v2 Pro Requests\' and limit \'RequestsPerDay\' of service \'generativelanguage.googleapis.com\' for consumer \'project_number:123456789\'.","status":"RESOURCE_EXHAUSTED"}}'; + + const result15 = parseAndFormatApiError( + errorMessage15, + AuthType.LOGIN_WITH_GOOGLE, + undefined, + 'gemini-1.5-pro', + DEFAULT_GEMINI_FLASH_MODEL, + ); + const resultPreview = parseAndFormatApiError( + errorMessagePreview, + AuthType.LOGIN_WITH_GOOGLE, + undefined, + 'gemini-2.5-preview-pro', + DEFAULT_GEMINI_FLASH_MODEL, + ); + const resultBeta = parseAndFormatApiError( + errorMessageBeta, + AuthType.LOGIN_WITH_GOOGLE, + undefined, + 'gemini-beta-3.0-pro', + DEFAULT_GEMINI_FLASH_MODEL, + ); + const resultExperimental = parseAndFormatApiError( + errorMessageExperimental, + AuthType.LOGIN_WITH_GOOGLE, + undefined, + 'gemini-experimental-v2-pro', + DEFAULT_GEMINI_FLASH_MODEL, + ); + + expect(result15).toContain( + 'You have reached your daily gemini-1.5-pro quota limit', + ); + expect(resultPreview).toContain( + 'You have reached your daily gemini-2.5-preview-pro quota limit', + ); + expect(resultBeta).toContain( + 'You have reached your daily gemini-beta-3.0-pro quota limit', + ); + expect(resultExperimental).toContain( + 'You have reached your daily gemini-experimental-v2-pro quota limit', + ); + expect(result15).toContain( + 'upgrade to a Gemini Code Assist Standard or Enterprise plan', + ); + expect(resultPreview).toContain( + 'upgrade to a Gemini Code Assist Standard or Enterprise plan', + ); + expect(resultBeta).toContain( + 'upgrade to a Gemini Code Assist Standard or Enterprise plan', + ); + expect(resultExperimental).toContain( + 'upgrade to a Gemini Code Assist Standard or Enterprise plan', + ); + }); + + it('should not match non-Pro models with similar version strings', () => { + // Test that Flash models with similar version strings don't match + expect( + isProQuotaExceededError( + "Quota exceeded for quota metric 'Gemini 2.5 Flash Requests' and limit", + ), + ).toBe(false); + expect( + isProQuotaExceededError( + "Quota exceeded for quota metric 'Gemini 2.5-preview Flash Requests' and limit", + ), + ).toBe(false); + expect( + isProQuotaExceededError( + "Quota exceeded for quota metric 'Gemini beta-3.0 Flash Requests' and limit", + ), + ).toBe(false); + expect( + isProQuotaExceededError( + "Quota exceeded for quota metric 'Gemini experimental-v2 Flash Requests' and limit", + ), + ).toBe(false); + + // Test other model types + expect( + isProQuotaExceededError( + "Quota exceeded for quota metric 'Gemini 2.5 Ultra Requests' and limit", + ), + ).toBe(false); + expect( + isProQuotaExceededError( + "Quota exceeded for quota metric 'Gemini 2.5 Standard Requests' and limit", + ), + ).toBe(false); + + // Test generic quota messages + expect( + isProQuotaExceededError( + "Quota exceeded for quota metric 'GenerationRequests' and limit", + ), + ).toBe(false); + expect( + isProQuotaExceededError( + "Quota exceeded for quota metric 'EmbeddingRequests' and limit", + ), + ).toBe(false); + }); + + it('should format a generic quota exceeded message for Google auth (Standard tier)', () => { + const errorMessage = + 'got status: 429 Too Many Requests. {"error":{"code":429,"message":"Quota exceeded for quota metric \'GenerationRequests\' and limit \'RequestsPerDay\' of service \'generativelanguage.googleapis.com\' for consumer \'project_number:123456789\'.","status":"RESOURCE_EXHAUSTED"}}'; + const result = parseAndFormatApiError( + errorMessage, + AuthType.LOGIN_WITH_GOOGLE, + UserTierId.STANDARD, + 'gemini-2.5-pro', + DEFAULT_GEMINI_FLASH_MODEL, + ); + expect(result).toContain( + "[API Error: Quota exceeded for quota metric 'GenerationRequests'", + ); + expect(result).toContain('You have reached your daily quota limit'); + expect(result).toContain( + 'We appreciate you for choosing Gemini Code Assist and the Gemini CLI', + ); + expect(result).not.toContain( + 'upgrade to a Gemini Code Assist Standard or Enterprise plan', + ); + }); + + it('should format a regular 429 API error with standard message for Google auth (Standard tier)', () => { + const errorMessage = + 'got status: 429 Too Many Requests. {"error":{"code":429,"message":"Rate limit exceeded","status":"RESOURCE_EXHAUSTED"}}'; + const result = parseAndFormatApiError( + errorMessage, + AuthType.LOGIN_WITH_GOOGLE, + UserTierId.STANDARD, + 'gemini-2.5-pro', + DEFAULT_GEMINI_FLASH_MODEL, + ); + expect(result).toContain('[API Error: Rate limit exceeded'); + expect(result).toContain( + 'We appreciate you for choosing Gemini Code Assist and the Gemini CLI', + ); + expect(result).not.toContain( + 'upgrade to a Gemini Code Assist Standard or Enterprise plan', + ); + }); }); |
