mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-10 14:10:37 -07:00
fix(core): parse raw ASCII buffer strings in Gaxios errors (#20626)
This commit is contained in:
@@ -243,6 +243,78 @@ describe('LoggingContentGenerator', () => {
|
|||||||
expect(errorEvent.error_type).toBe('FatalAuthenticationError');
|
expect(errorEvent.error_type).toBe('FatalAuthenticationError');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Gaxios error parsing', () => {
|
||||||
|
it('should parse raw ASCII buffer strings in Gaxios errors', async () => {
|
||||||
|
const req = { contents: [], model: 'gemini-pro' };
|
||||||
|
|
||||||
|
// Simulate a Gaxios error with comma-separated ASCII codes
|
||||||
|
const asciiData = '72,101,108,108,111'; // "Hello"
|
||||||
|
const gaxiosError = Object.assign(new Error('Gaxios Error'), {
|
||||||
|
response: { data: asciiData },
|
||||||
|
});
|
||||||
|
|
||||||
|
vi.mocked(wrapped.generateContent).mockRejectedValue(gaxiosError);
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
loggingContentGenerator.generateContent(
|
||||||
|
req,
|
||||||
|
'prompt-123',
|
||||||
|
LlmRole.MAIN,
|
||||||
|
),
|
||||||
|
).rejects.toSatisfy((error: unknown) => {
|
||||||
|
const gError = error as { response: { data: unknown } };
|
||||||
|
expect(gError.response.data).toBe('Hello');
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should leave data alone if it is not a comma-separated string', async () => {
|
||||||
|
const req = { contents: [], model: 'gemini-pro' };
|
||||||
|
|
||||||
|
const normalData = 'Normal error message';
|
||||||
|
const gaxiosError = Object.assign(new Error('Gaxios Error'), {
|
||||||
|
response: { data: normalData },
|
||||||
|
});
|
||||||
|
|
||||||
|
vi.mocked(wrapped.generateContent).mockRejectedValue(gaxiosError);
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
loggingContentGenerator.generateContent(
|
||||||
|
req,
|
||||||
|
'prompt-123',
|
||||||
|
LlmRole.MAIN,
|
||||||
|
),
|
||||||
|
).rejects.toSatisfy((error: unknown) => {
|
||||||
|
const gError = error as { response: { data: unknown } };
|
||||||
|
expect(gError.response.data).toBe(normalData);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should leave data alone if parsing fails', async () => {
|
||||||
|
const req = { contents: [], model: 'gemini-pro' };
|
||||||
|
|
||||||
|
const invalidAscii = '72,invalid,101';
|
||||||
|
const gaxiosError = Object.assign(new Error('Gaxios Error'), {
|
||||||
|
response: { data: invalidAscii },
|
||||||
|
});
|
||||||
|
|
||||||
|
vi.mocked(wrapped.generateContent).mockRejectedValue(gaxiosError);
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
loggingContentGenerator.generateContent(
|
||||||
|
req,
|
||||||
|
'prompt-123',
|
||||||
|
LlmRole.MAIN,
|
||||||
|
),
|
||||||
|
).rejects.toSatisfy((error: unknown) => {
|
||||||
|
const gError = error as { response: { data: unknown } };
|
||||||
|
expect(gError.response.data).toBe(invalidAscii);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('generateContentStream', () => {
|
describe('generateContentStream', () => {
|
||||||
|
|||||||
@@ -274,6 +274,32 @@ export class LoggingContentGenerator implements ContentGenerator {
|
|||||||
logApiResponse(this.config, event);
|
logApiResponse(this.config, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _fixGaxiosErrorData(error: unknown): void {
|
||||||
|
// Fix for raw ASCII buffer strings appearing in dev with the latest
|
||||||
|
// Gaxios updates.
|
||||||
|
if (
|
||||||
|
typeof error === 'object' &&
|
||||||
|
error !== null &&
|
||||||
|
'response' in error &&
|
||||||
|
typeof error.response === 'object' &&
|
||||||
|
error.response !== null &&
|
||||||
|
'data' in error.response
|
||||||
|
) {
|
||||||
|
const response = error.response as { data: unknown };
|
||||||
|
const data = response.data;
|
||||||
|
if (typeof data === 'string' && data.includes(',')) {
|
||||||
|
try {
|
||||||
|
const charCodes = data.split(',').map(Number);
|
||||||
|
if (charCodes.every((code) => !isNaN(code))) {
|
||||||
|
response.data = String.fromCharCode(...charCodes);
|
||||||
|
}
|
||||||
|
} catch (_e) {
|
||||||
|
// If parsing fails, just leave it alone
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private _logApiError(
|
private _logApiError(
|
||||||
durationMs: number,
|
durationMs: number,
|
||||||
error: unknown,
|
error: unknown,
|
||||||
@@ -380,6 +406,9 @@ export class LoggingContentGenerator implements ContentGenerator {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
spanMetadata.error = error;
|
spanMetadata.error = error;
|
||||||
const durationMs = Date.now() - startTime;
|
const durationMs = Date.now() - startTime;
|
||||||
|
|
||||||
|
this._fixGaxiosErrorData(error);
|
||||||
|
|
||||||
this._logApiError(
|
this._logApiError(
|
||||||
durationMs,
|
durationMs,
|
||||||
error,
|
error,
|
||||||
@@ -447,6 +476,9 @@ export class LoggingContentGenerator implements ContentGenerator {
|
|||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const durationMs = Date.now() - startTime;
|
const durationMs = Date.now() - startTime;
|
||||||
|
|
||||||
|
this._fixGaxiosErrorData(error);
|
||||||
|
|
||||||
this._logApiError(
|
this._logApiError(
|
||||||
durationMs,
|
durationMs,
|
||||||
error,
|
error,
|
||||||
|
|||||||
Reference in New Issue
Block a user