chore: revert unnecessary eslint-disable changes and unrelated telemetry removals

This commit is contained in:
Spencer
2026-03-20 05:51:13 +00:00
parent 1da234f68c
commit a974d72399
12 changed files with 89 additions and 2 deletions
@@ -159,11 +159,13 @@ async function truncateHistoryToBudget(
} else if (responseObj && typeof responseObj === 'object') {
if (
'output' in responseObj &&
typeof responseObj['output'] === 'string'
) {
contentStr = responseObj['output'];
} else if (
'content' in responseObj &&
typeof responseObj['content'] === 'string'
) {
contentStr = responseObj['content'];
@@ -362,6 +362,7 @@ export class HookAggregator {
// Extract additionalContext from various hook types
if (
'additionalContext' in specific &&
typeof specific['additionalContext'] === 'string'
) {
contexts.push(specific['additionalContext']);
@@ -584,10 +584,12 @@ export class LoopDetectionService {
}
const flashConfidence =
typeof flashResult['unproductive_state_confidence'] === 'number'
? flashResult['unproductive_state_confidence']
: 0;
const flashAnalysis =
typeof flashResult['unproductive_state_analysis'] === 'string'
? flashResult['unproductive_state_analysis']
: '';
@@ -634,11 +636,13 @@ export class LoopDetectionService {
const mainModelConfidence =
mainModelResult &&
typeof mainModelResult['unproductive_state_confidence'] === 'number'
? mainModelResult['unproductive_state_confidence']
: 0;
const mainModelAnalysis =
mainModelResult &&
typeof mainModelResult['unproductive_state_analysis'] === 'string'
? mainModelResult['unproductive_state_analysis']
: undefined;
@@ -687,6 +691,7 @@ export class LoopDetectionService {
if (
result &&
typeof result['unproductive_state_confidence'] === 'number'
) {
return result;
@@ -21,6 +21,7 @@ import type {
RewindEvent,
MalformedJsonResponseEvent,
IdeConnectionEvent,
ConversationFinishedEvent,
ChatCompressionEvent,
FileOperationEvent,
InvalidChunkEvent,
@@ -1149,6 +1150,28 @@ export class ClearcutLogger {
});
}
logConversationFinishedEvent(event: ConversationFinishedEvent): void {
const data: EventValue[] = [
{
gemini_cli_key: EventMetadataKey.GEMINI_CLI_SESSION_ID,
value: this.config?.getSessionId() ?? '',
},
{
gemini_cli_key: EventMetadataKey.GEMINI_CLI_CONVERSATION_TURN_COUNT,
value: JSON.stringify(event.turnCount),
},
{
gemini_cli_key: EventMetadataKey.GEMINI_CLI_APPROVAL_MODE,
value: event.approvalMode,
},
];
this.enqueueLogEvent(
this.createLogEvent(EventNames.CONVERSATION_FINISHED, data),
);
this.flushIfNeeded();
}
logEndSessionEvent(): void {
// Flush immediately on session end.
this.enqueueLogEvent(this.createLogEvent(EventNames.END_SESSION, []));
+2
View File
@@ -38,6 +38,7 @@ export {
logApiResponse,
logFlashFallback,
logSlashCommand,
logConversationFinishedEvent,
logChatCompression,
logToolOutputTruncated,
logExtensionEnable,
@@ -65,6 +66,7 @@ export {
FlashFallbackEvent,
StartSessionEvent,
ToolCallEvent,
ConversationFinishedEvent,
ToolOutputTruncatedEvent,
WebFetchFallbackAttemptEvent,
NetworkRetryAttemptEvent,
+16
View File
@@ -26,6 +26,7 @@ import {
type LoopDetectionDisabledEvent,
type SlashCommandEvent,
type RewindEvent,
type ConversationFinishedEvent,
type ChatCompressionEvent,
type MalformedJsonResponseEvent,
type InvalidChunkEvent,
@@ -435,6 +436,21 @@ export function logIdeConnection(
});
}
export function logConversationFinishedEvent(
config: Config,
event: ConversationFinishedEvent,
): void {
ClearcutLogger.getInstance(config)?.logConversationFinishedEvent(event);
bufferTelemetryEvent(() => {
const logger = logs.getLogger(SERVICE_NAME);
const logRecord: LogRecord = {
body: event.toLogBody(),
attributes: event.toOpenTelemetryAttributes(config),
};
logger.emit(logRecord);
});
}
export function logChatCompression(
config: Config,
event: ChatCompressionEvent,
+2
View File
@@ -63,6 +63,7 @@ function getStringReferences(parts: AnyPart[]): StringReference[] {
});
}
} else if (part instanceof GenericPart) {
if (part.type === 'executableCode' && typeof part['code'] === 'string') {
refs.push({
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
@@ -73,6 +74,7 @@ function getStringReferences(parts: AnyPart[]): StringReference[] {
});
} else if (
part.type === 'codeExecutionResult' &&
typeof part['output'] === 'string'
) {
refs.push({
+30
View File
@@ -1184,6 +1184,35 @@ export class IdeConnectionEvent {
}
}
export const EVENT_CONVERSATION_FINISHED = 'gemini_cli.conversation_finished';
export class ConversationFinishedEvent {
'event_name': 'conversation_finished';
'event.timestamp': string; // ISO 8601;
approvalMode: ApprovalMode;
turnCount: number;
constructor(approvalMode: ApprovalMode, turnCount: number) {
this['event_name'] = 'conversation_finished';
this['event.timestamp'] = new Date().toISOString();
this.approvalMode = approvalMode;
this.turnCount = turnCount;
}
toOpenTelemetryAttributes(config: Config): LogAttributes {
return {
...getCommonAttributes(config),
'event.name': EVENT_CONVERSATION_FINISHED,
'event.timestamp': this['event.timestamp'],
approvalMode: this.approvalMode,
turnCount: this.turnCount,
};
}
toLogBody(): string {
return `Conversation finished.`;
}
}
export const EVENT_FILE_OPERATION = 'gemini_cli.file_operation';
export class FileOperationEvent implements BaseTelemetryEvent {
'event.name': 'file_operation';
@@ -1817,6 +1846,7 @@ export type TelemetryEvent =
| NextSpeakerCheckEvent
| MalformedJsonResponseEvent
| IdeConnectionEvent
| ConversationFinishedEvent
| SlashCommandEvent
| FileOperationEvent
| InvalidChunkEvent
@@ -19,6 +19,7 @@ export function createMockWorkspaceContext(
): WorkspaceContext {
const allDirs = [rootDir, ...additionalDirs];
const mockWorkspaceContext = {
addDirectory: vi.fn(),
getDirectories: vi.fn().mockReturnValue(allDirs),
+1
View File
@@ -112,6 +112,7 @@ Return ONLY the corrected string in the specified JSON format with the key 'corr
if (
result &&
typeof result['corrected_string_escaping'] === 'string' &&
result['corrected_string_escaping'].length > 0
) {
+1 -1
View File
@@ -231,7 +231,7 @@ export function parseGoogleApiError(error: unknown): GoogleApiError | null {
}
// Basic structural check before casting.
// Since the proto definitions are loose, we primarily rely on @type presence.
if (typeof detailObj['@type'] === 'string') {
// We can just cast it; the consumer will have to switch on @type
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
+5 -1
View File
@@ -361,20 +361,24 @@ async function parseTokenEndpointResponse(
data &&
typeof data === 'object' &&
'access_token' in data &&
typeof (data as Record<string, unknown>)['access_token'] === 'string'
) {
const obj = data as Record<string, unknown>;
const result: OAuthTokenResponse = {
access_token: String(obj['access_token']),
token_type:
typeof obj['token_type'] === 'string' ? obj['token_type'] : 'Bearer',
expires_in:
typeof obj['expires_in'] === 'number' ? obj['expires_in'] : undefined,
refresh_token:
typeof obj['refresh_token'] === 'string'
? obj['refresh_token']
: undefined,
scope: typeof obj['scope'] === 'string' ? obj['scope'] : undefined,
};
return result;