Disallow unsafe type assertions (#18688)

This commit is contained in:
Christian Gunderman
2026-02-10 00:10:15 +00:00
committed by GitHub
parent bce1caefd0
commit fd65416a2f
188 changed files with 592 additions and 47 deletions
@@ -174,6 +174,7 @@ export class ActivityMonitor {
eventTypes: Record<ActivityType, number>;
timeRange: { start: number; end: number } | null;
} {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
const eventTypes = {} as Record<ActivityType, number>;
let start = Number.MAX_SAFE_INTEGER;
let end = 0;
@@ -450,6 +450,7 @@ export class ClearcutLogger {
if (this.config?.getDebugMode()) {
debugLogger.log('Flushing log events to Clearcut.');
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
const eventsToSend = this.events.toArray() as LogEventEntry[][];
this.events.clear();
@@ -493,6 +494,7 @@ export class ClearcutLogger {
}
} catch (e: unknown) {
if (this.config?.getDebugMode()) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
debugLogger.warn('Error flushing log events:', e as Error);
}
@@ -104,6 +104,7 @@ export class GcpLogExporter implements LogRecordExporter {
} catch (error) {
resultCallback({
code: ExportResultCode.FAILED,
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
error: error as Error,
});
}
@@ -15,6 +15,7 @@ import type { Config } from '../config/config.js';
describe('Circular Reference Integration Test', () => {
it('should handle HttpsProxyAgent-like circular references in clearcut logging', () => {
// Create a mock config with proxy
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
const mockConfig = {
getTelemetryEnabled: () => true,
getUsageStatisticsEnabled: () => true,
@@ -56,7 +57,7 @@ describe('Circular Reference Integration Test', () => {
const logger = ClearcutLogger.getInstance(mockConfig);
expect(() => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-type-assertion
logger?.enqueueLogEvent(problematicEvent as any);
}).not.toThrow();
});
@@ -22,6 +22,7 @@ import { MockTool } from '../test-utils/mock-tool.js';
describe('Circular Reference Handling', () => {
it('should handle circular references in tool function arguments', () => {
// Create a mock config
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
const mockConfig = {
getTelemetryEnabled: () => true,
getUsageStatisticsEnabled: () => true,
@@ -78,6 +79,7 @@ describe('Circular Reference Handling', () => {
});
it('should handle normal objects without circular references', () => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
const mockConfig = {
getTelemetryEnabled: () => true,
getUsageStatisticsEnabled: () => true,
+4
View File
@@ -111,6 +111,7 @@ export function logUserPrompt(config: Config, event: UserPromptEvent): void {
}
export function logToolCall(config: Config, event: ToolCallEvent): void {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
const uiEvent = {
...event,
'event.name': EVENT_TOOL_CALL,
@@ -242,6 +243,7 @@ export function logRipgrepFallback(
}
export function logApiError(config: Config, event: ApiErrorEvent): void {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
const uiEvent = {
...event,
'event.name': EVENT_API_ERROR,
@@ -273,6 +275,7 @@ export function logApiError(config: Config, event: ApiErrorEvent): void {
}
export function logApiResponse(config: Config, event: ApiResponseEvent): void {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
const uiEvent = {
...event,
'event.name': EVENT_API_RESPONSE,
@@ -372,6 +375,7 @@ export function logSlashCommand(
}
export function logRewind(config: Config, event: RewindEvent): void {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
const uiEvent = {
...event,
'event.name': EVENT_REWIND,
+30
View File
@@ -77,6 +77,7 @@ const COUNTER_DEFINITIONS = {
description: 'Counts tool calls, tagged by function name and success.',
valueType: ValueType.INT,
assign: (c: Counter) => (toolCallCounter = c),
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
attributes: {} as {
function_name: string;
success: boolean;
@@ -88,6 +89,7 @@ const COUNTER_DEFINITIONS = {
description: 'Counts API requests, tagged by model and status.',
valueType: ValueType.INT,
assign: (c: Counter) => (apiRequestCounter = c),
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
attributes: {} as {
model: string;
status_code?: number | string;
@@ -98,6 +100,7 @@ const COUNTER_DEFINITIONS = {
description: 'Counts the total number of tokens used.',
valueType: ValueType.INT,
assign: (c: Counter) => (tokenUsageCounter = c),
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
attributes: {} as {
model: string;
type: 'input' | 'output' | 'thought' | 'cache' | 'tool';
@@ -113,6 +116,7 @@ const COUNTER_DEFINITIONS = {
description: 'Counts file operations (create, read, update).',
valueType: ValueType.INT,
assign: (c: Counter) => (fileOperationCounter = c),
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
attributes: {} as {
operation: FileOperation;
lines?: number;
@@ -125,6 +129,7 @@ const COUNTER_DEFINITIONS = {
description: 'Number of lines changed (from file diffs).',
valueType: ValueType.INT,
assign: (c: Counter) => (linesChangedCounter = c),
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
attributes: {} as {
function_name?: string;
type: 'added' | 'removed';
@@ -152,6 +157,7 @@ const COUNTER_DEFINITIONS = {
description: 'Counts model routing failures.',
valueType: ValueType.INT,
assign: (c: Counter) => (modelRoutingFailureCounter = c),
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
attributes: {} as {
'routing.decision_source': string;
'routing.error_message': string;
@@ -161,6 +167,7 @@ const COUNTER_DEFINITIONS = {
description: 'Counts model slash command calls.',
valueType: ValueType.INT,
assign: (c: Counter) => (modelSlashCommandCallCounter = c),
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
attributes: {} as {
'slash_command.model.model_name': string;
},
@@ -169,6 +176,7 @@ const COUNTER_DEFINITIONS = {
description: 'Counts chat compression events.',
valueType: ValueType.INT,
assign: (c: Counter) => (chatCompressionCounter = c),
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
attributes: {} as {
tokens_before: number;
tokens_after: number;
@@ -178,6 +186,7 @@ const COUNTER_DEFINITIONS = {
description: 'Counts agent runs, tagged by name and termination reason.',
valueType: ValueType.INT,
assign: (c: Counter) => (agentRunCounter = c),
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
attributes: {} as {
agent_name: string;
terminate_reason: string;
@@ -187,6 +196,7 @@ const COUNTER_DEFINITIONS = {
description: 'Counts agent recovery attempts.',
valueType: ValueType.INT,
assign: (c: Counter) => (agentRecoveryAttemptCounter = c),
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
attributes: {} as {
agent_name: string;
reason: string;
@@ -210,6 +220,7 @@ const COUNTER_DEFINITIONS = {
description: 'Counts plan executions (switching from Plan Mode).',
valueType: ValueType.INT,
assign: (c: Counter) => (planExecutionCounter = c),
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
attributes: {} as {
approval_mode: string;
},
@@ -218,6 +229,7 @@ const COUNTER_DEFINITIONS = {
description: 'Counts hook calls, tagged by hook event name and success.',
valueType: ValueType.INT,
assign: (c: Counter) => (hookCallCounter = c),
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
attributes: {} as {
hook_event_name: string;
hook_name: string;
@@ -232,6 +244,7 @@ const HISTOGRAM_DEFINITIONS = {
unit: 'ms',
valueType: ValueType.INT,
assign: (h: Histogram) => (toolCallLatencyHistogram = h),
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
attributes: {} as {
function_name: string;
},
@@ -241,6 +254,7 @@ const HISTOGRAM_DEFINITIONS = {
unit: 'ms',
valueType: ValueType.INT,
assign: (h: Histogram) => (apiRequestLatencyHistogram = h),
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
attributes: {} as {
model: string;
},
@@ -250,6 +264,7 @@ const HISTOGRAM_DEFINITIONS = {
unit: 'ms',
valueType: ValueType.INT,
assign: (h: Histogram) => (modelRoutingLatencyHistogram = h),
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
attributes: {} as {
'routing.decision_model': string;
'routing.decision_source': string;
@@ -260,6 +275,7 @@ const HISTOGRAM_DEFINITIONS = {
unit: 'ms',
valueType: ValueType.INT,
assign: (h: Histogram) => (agentDurationHistogram = h),
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
attributes: {} as {
agent_name: string;
},
@@ -276,6 +292,7 @@ const HISTOGRAM_DEFINITIONS = {
unit: 'turns',
valueType: ValueType.INT,
assign: (h: Histogram) => (agentTurnsHistogram = h),
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
attributes: {} as {
agent_name: string;
},
@@ -285,6 +302,7 @@ const HISTOGRAM_DEFINITIONS = {
unit: 'ms',
valueType: ValueType.INT,
assign: (h: Histogram) => (agentRecoveryAttemptDurationHistogram = h),
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
attributes: {} as {
agent_name: string;
},
@@ -294,6 +312,7 @@ const HISTOGRAM_DEFINITIONS = {
unit: 'token',
valueType: ValueType.INT,
assign: (h: Histogram) => (genAiClientTokenUsageHistogram = h),
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
attributes: {} as {
'gen_ai.operation.name': string;
'gen_ai.provider.name': string;
@@ -309,6 +328,7 @@ const HISTOGRAM_DEFINITIONS = {
unit: 's',
valueType: ValueType.DOUBLE,
assign: (h: Histogram) => (genAiClientOperationDurationHistogram = h),
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
attributes: {} as {
'gen_ai.operation.name': string;
'gen_ai.provider.name': string;
@@ -324,6 +344,7 @@ const HISTOGRAM_DEFINITIONS = {
unit: 'ms',
valueType: ValueType.INT,
assign: (c: Histogram) => (hookCallLatencyHistogram = c),
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
attributes: {} as {
hook_event_name: string;
hook_name: string;
@@ -337,6 +358,7 @@ const PERFORMANCE_COUNTER_DEFINITIONS = {
description: 'Performance regression detection events.',
valueType: ValueType.INT,
assign: (c: Counter) => (regressionDetectionCounter = c),
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
attributes: {} as {
metric: string;
severity: 'low' | 'medium' | 'high';
@@ -353,6 +375,7 @@ const PERFORMANCE_HISTOGRAM_DEFINITIONS = {
unit: 'ms',
valueType: ValueType.DOUBLE,
assign: (h: Histogram) => (startupTimeHistogram = h),
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
attributes: {} as {
phase: string;
details?: Record<string, string | number | boolean>;
@@ -363,6 +386,7 @@ const PERFORMANCE_HISTOGRAM_DEFINITIONS = {
unit: 'bytes',
valueType: ValueType.INT,
assign: (h: Histogram) => (memoryUsageGauge = h),
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
attributes: {} as {
memory_type: MemoryMetricType;
component?: string;
@@ -389,6 +413,7 @@ const PERFORMANCE_HISTOGRAM_DEFINITIONS = {
unit: 'ms',
valueType: ValueType.INT,
assign: (h: Histogram) => (toolExecutionBreakdownHistogram = h),
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
attributes: {} as {
function_name: string;
phase: ToolExecutionPhase;
@@ -400,6 +425,7 @@ const PERFORMANCE_HISTOGRAM_DEFINITIONS = {
unit: 'ratio',
valueType: ValueType.DOUBLE,
assign: (h: Histogram) => (tokenEfficiencyHistogram = h),
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
attributes: {} as {
model: string;
metric: string;
@@ -411,6 +437,7 @@ const PERFORMANCE_HISTOGRAM_DEFINITIONS = {
unit: 'ms',
valueType: ValueType.INT,
assign: (h: Histogram) => (apiRequestBreakdownHistogram = h),
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
attributes: {} as {
model: string;
phase: ApiRequestPhase;
@@ -421,6 +448,7 @@ const PERFORMANCE_HISTOGRAM_DEFINITIONS = {
unit: 'score',
valueType: ValueType.DOUBLE,
assign: (h: Histogram) => (performanceScoreGauge = h),
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
attributes: {} as {
category: string;
baseline?: number;
@@ -432,6 +460,7 @@ const PERFORMANCE_HISTOGRAM_DEFINITIONS = {
unit: 'percent',
valueType: ValueType.DOUBLE,
assign: (h: Histogram) => (regressionPercentageChangeHistogram = h),
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
attributes: {} as {
metric: string;
severity: 'low' | 'medium' | 'high';
@@ -445,6 +474,7 @@ const PERFORMANCE_HISTOGRAM_DEFINITIONS = {
unit: 'percent',
valueType: ValueType.DOUBLE,
assign: (h: Histogram) => (baselineComparisonHistogram = h),
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
attributes: {} as {
metric: string;
category: string;
+4
View File
@@ -65,8 +65,10 @@ 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
get: () => part['code'] as string,
set: (val: string) => (part['code'] = val),
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
len: () => (part['code'] as string).length,
});
} else if (
@@ -74,8 +76,10 @@ function getStringReferences(parts: AnyPart[]): StringReference[] {
typeof part['output'] === 'string'
) {
refs.push({
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
get: () => part['output'] as string,
set: (val: string) => (part['output'] = val),
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
len: () => (part['output'] as string).length,
});
}
+1
View File
@@ -316,6 +316,7 @@ export class ToolCallEvent implements BaseTelemetryEvent {
}
}
} else {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
this.function_name = function_name as string;
this.function_args = function_args!;
this.duration_ms = duration_ms!;