Migrate console to coreEvents.emitFeedback or debugLogger (#15219)

This commit is contained in:
Adib234
2025-12-29 15:46:10 -05:00
committed by GitHub
parent dcd2449b1a
commit 10ae84869a
66 changed files with 564 additions and 425 deletions
+1
View File
@@ -4,6 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
/* eslint-disable no-console */
import * as fs from 'node:fs';
import * as util from 'node:util';
+5 -4
View File
@@ -22,6 +22,7 @@ import {
} from '../utils/messageInspectors.js';
import * as fs from 'node:fs';
import { promptIdContext } from './promptIdContext.js';
import { debugLogger } from './debugLogger.js';
const CODE_CORRECTION_SYSTEM_PROMPT = `
You are an expert code-editing assistant. Your task is to analyze a failed edit attempt and provide a corrected version of the text snippets.
@@ -434,7 +435,7 @@ Return ONLY the corrected target snippet in the specified JSON format with the k
throw error;
}
console.error(
debugLogger.warn(
'Error during LLM call for old string snippet correction:',
error,
);
@@ -523,7 +524,7 @@ Return ONLY the corrected string in the specified JSON format with the key 'corr
throw error;
}
console.error('Error during LLM call for new_string correction:', error);
debugLogger.warn('Error during LLM call for new_string correction:', error);
return originalNewString;
}
}
@@ -593,7 +594,7 @@ Return ONLY the corrected string in the specified JSON format with the key 'corr
throw error;
}
console.error(
debugLogger.warn(
'Error during LLM call for new_string escaping correction:',
error,
);
@@ -660,7 +661,7 @@ Return ONLY the corrected string in the specified JSON format with the key 'corr
throw error;
}
console.error(
debugLogger.warn(
'Error during LLM call for string escaping correction:',
error,
);
+25 -14
View File
@@ -9,12 +9,13 @@ import fs from 'node:fs/promises';
import os from 'node:os';
import path from 'node:path';
import { reportError } from './errorReporting.js';
import { debugLogger } from './debugLogger.js';
// Use a type alias for SpyInstance as it's not directly exported
type SpyInstance = ReturnType<typeof vi.spyOn>;
describe('reportError', () => {
let consoleErrorSpy: SpyInstance;
let debugLoggerErrorSpy: SpyInstance;
let testDir: string;
const MOCK_TIMESTAMP = '2025-01-01T00-00-00-000Z';
@@ -22,7 +23,9 @@ describe('reportError', () => {
// Create a temporary directory for logs
testDir = await fs.mkdtemp(path.join(os.tmpdir(), 'gemini-report-test-'));
vi.resetAllMocks();
consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
debugLoggerErrorSpy = vi
.spyOn(debugLogger, 'error')
.mockImplementation(() => {});
vi.spyOn(Date.prototype, 'toISOString').mockReturnValue(MOCK_TIMESTAMP);
});
@@ -54,9 +57,10 @@ describe('reportError', () => {
context,
});
// Verify the console log
expect(consoleErrorSpy).toHaveBeenCalledWith(
// Verify the user feedback
expect(debugLoggerErrorSpy).toHaveBeenCalledWith(
`${baseMessage} Full report available at: ${expectedReportPath}`,
error,
);
});
@@ -75,8 +79,9 @@ describe('reportError', () => {
error: { message: 'Test plain object error' },
});
expect(consoleErrorSpy).toHaveBeenCalledWith(
expect(debugLoggerErrorSpy).toHaveBeenCalledWith(
`${baseMessage} Full report available at: ${expectedReportPath}`,
error,
);
});
@@ -95,8 +100,9 @@ describe('reportError', () => {
error: { message: 'Just a string error' },
});
expect(consoleErrorSpy).toHaveBeenCalledWith(
expect(debugLoggerErrorSpy).toHaveBeenCalledWith(
`${baseMessage} Full report available at: ${expectedReportPath}`,
error,
);
});
@@ -109,15 +115,18 @@ describe('reportError', () => {
await reportError(error, baseMessage, context, type, nonExistentDir);
expect(consoleErrorSpy).toHaveBeenCalledWith(
expect(debugLoggerErrorSpy).toHaveBeenCalledWith(
`${baseMessage} Additionally, failed to write detailed error report:`,
expect.any(Error), // The actual write error
);
expect(consoleErrorSpy).toHaveBeenCalledWith(
expect(debugLoggerErrorSpy).toHaveBeenCalledWith(
'Original error that triggered report generation:',
error,
);
expect(consoleErrorSpy).toHaveBeenCalledWith('Original context:', context);
expect(debugLoggerErrorSpy).toHaveBeenCalledWith(
'Original context:',
context,
);
});
it('should handle stringification failure of report content (e.g. BigInt in context)', async () => {
@@ -146,15 +155,15 @@ describe('reportError', () => {
await reportError(error, baseMessage, context, type, testDir);
expect(consoleErrorSpy).toHaveBeenCalledWith(
expect(debugLoggerErrorSpy).toHaveBeenCalledWith(
`${baseMessage} Could not stringify report content (likely due to context):`,
stringifyError,
);
expect(consoleErrorSpy).toHaveBeenCalledWith(
expect(debugLoggerErrorSpy).toHaveBeenCalledWith(
'Original error that triggered report generation:',
error,
);
expect(consoleErrorSpy).toHaveBeenCalledWith(
expect(debugLoggerErrorSpy).toHaveBeenCalledWith(
'Original context could not be stringified or included in report.',
);
@@ -165,8 +174,9 @@ describe('reportError', () => {
error: { message: error.message, stack: error.stack },
});
expect(consoleErrorSpy).toHaveBeenCalledWith(
expect(debugLoggerErrorSpy).toHaveBeenCalledWith(
`${baseMessage} Partial report (excluding context) available at: ${expectedMinimalReportPath}`,
error,
);
});
@@ -186,8 +196,9 @@ describe('reportError', () => {
error: { message: 'Error without context', stack: 'No context stack' },
});
expect(consoleErrorSpy).toHaveBeenCalledWith(
expect(debugLoggerErrorSpy).toHaveBeenCalledWith(
`${baseMessage} Full report available at: ${expectedReportPath}`,
error,
);
});
});
+26 -12
View File
@@ -8,6 +8,7 @@ import fs from 'node:fs/promises';
import os from 'node:os';
import path from 'node:path';
import type { Content } from '@google/genai';
import { debugLogger } from './debugLogger.js';
interface ErrorReportData {
error: { message: string; stack?: string } | { message: string };
@@ -16,7 +17,7 @@ interface ErrorReportData {
}
/**
* Generates an error report, writes it to a temporary file, and logs information to console.error.
* Generates an error report, writes it to a temporary file, and logs information to user
* @param error The error object.
* @param context The relevant context (e.g., chat history, request contents).
* @param type A string to identify the type of error (e.g., 'startChat', 'generateJson-api').
@@ -59,13 +60,16 @@ export async function reportError(
stringifiedReportContent = JSON.stringify(reportContent, null, 2);
} catch (stringifyError) {
// This can happen if context contains something like BigInt
console.error(
debugLogger.error(
`${baseMessage} Could not stringify report content (likely due to context):`,
stringifyError,
);
console.error('Original error that triggered report generation:', error);
debugLogger.error(
'Original error that triggered report generation:',
error,
);
if (context) {
console.error(
debugLogger.error(
'Original context could not be stringified or included in report.',
);
}
@@ -75,11 +79,12 @@ export async function reportError(
stringifiedReportContent = JSON.stringify(minimalReportContent, null, 2);
// Still try to write the minimal report
await fs.writeFile(reportPath, stringifiedReportContent);
console.error(
debugLogger.error(
`${baseMessage} Partial report (excluding context) available at: ${reportPath}`,
error,
);
} catch (minimalWriteError) {
console.error(
debugLogger.error(
`${baseMessage} Failed to write even a minimal error report:`,
minimalWriteError,
);
@@ -89,28 +94,37 @@ export async function reportError(
try {
await fs.writeFile(reportPath, stringifiedReportContent);
console.error(`${baseMessage} Full report available at: ${reportPath}`);
debugLogger.error(
`${baseMessage} Full report available at: ${reportPath}`,
error,
);
} catch (writeError) {
console.error(
debugLogger.error(
`${baseMessage} Additionally, failed to write detailed error report:`,
writeError,
);
// Log the original error as a fallback if report writing fails
console.error('Original error that triggered report generation:', error);
debugLogger.error(
'Original error that triggered report generation:',
error,
);
if (context) {
// Context was stringifiable, but writing the file failed.
// We already have stringifiedReportContent, but it might be too large for console.
// So, we try to log the original context object, and if that fails, its stringified version (truncated).
try {
console.error('Original context:', context);
debugLogger.error('Original context:', context);
} catch {
try {
console.error(
debugLogger.error(
'Original context (stringified, truncated):',
JSON.stringify(context).substring(0, 1000),
);
} catch {
console.error('Original context could not be logged or stringified.');
debugLogger.error(
'Original context could not be logged or stringified.',
);
}
}
}
@@ -342,7 +342,10 @@ export async function getFolderStructure(
return `${summary}\n\n${resolvedPath}${path.sep}\n${structureLines.join('\n')}`;
} catch (error: unknown) {
console.error(`Error getting folder structure for ${resolvedPath}:`, error);
debugLogger.warn(
`Error getting folder structure for ${resolvedPath}:`,
error,
);
return `Error processing directory "${resolvedPath}": ${getErrorMessage(error)}`;
}
}
+1 -1
View File
@@ -31,7 +31,7 @@ const logger = {
debugLogger.warn('[WARN] [MemoryDiscovery]', ...args),
// eslint-disable-next-line @typescript-eslint/no-explicit-any
error: (...args: any[]) =>
console.error('[ERROR] [MemoryDiscovery]', ...args),
debugLogger.error('[ERROR] [MemoryDiscovery]', ...args),
};
export interface GeminiFileContent {
+4 -4
View File
@@ -232,7 +232,7 @@ export async function retryWithBackoff<T>(
continue;
}
} catch (fallbackError) {
console.warn('Model fallback failed:', fallbackError);
debugLogger.warn('Model fallback failed:', fallbackError);
}
}
throw classifiedError instanceof RetryableQuotaError
@@ -241,7 +241,7 @@ export async function retryWithBackoff<T>(
}
if (classifiedError instanceof RetryableQuotaError) {
console.warn(
debugLogger.warn(
`Attempt ${attempt} failed: ${classifiedError.message}. Retrying after ${classifiedError.retryDelayMs}ms...`,
);
await delay(classifiedError.retryDelayMs, signal);
@@ -300,7 +300,7 @@ function logRetryAttempt(
if (errorStatus === 429) {
debugLogger.warn(message, error);
} else if (errorStatus && errorStatus >= 500 && errorStatus < 600) {
console.error(message, error);
debugLogger.warn(message, error);
} else if (error instanceof Error) {
// Fallback for errors that might not have a status but have a message
if (error.message.includes('429')) {
@@ -309,7 +309,7 @@ function logRetryAttempt(
error,
);
} else if (error.message.match(/5\d{2}/)) {
console.error(
debugLogger.warn(
`Attempt ${attempt} failed with 5xx error. Retrying with backoff...`,
error,
);
+3 -2
View File
@@ -19,6 +19,7 @@ import type {
ResolvedModelConfig,
} from '../services/modelConfigService.js';
import { DEFAULT_GEMINI_MODEL } from '../config/models.js';
import { debugLogger } from './debugLogger.js';
// Mock GeminiClient and Config constructor
vi.mock('../core/client.js');
@@ -58,11 +59,11 @@ describe('summarizers', () => {
(mockGeminiClient.generateContent as Mock) = vi.fn();
vi.spyOn(console, 'error').mockImplementation(() => {});
vi.spyOn(debugLogger, 'warn').mockImplementation(() => {});
});
afterEach(() => {
vi.clearAllMocks();
(console.error as Mock).mockRestore();
vi.restoreAllMocks();
});
describe('summarizeToolOutput', () => {