telemetry: track interactive session state (#12856)

Co-authored-by: owenofbrien <86964623+owenofbrien@users.noreply.github.com>
This commit is contained in:
N. Taylor Mullen
2025-11-11 02:03:32 -08:00
committed by GitHub
parent e79f62694a
commit 7bb13d1c41
24 changed files with 132 additions and 25 deletions
@@ -52,6 +52,7 @@ const renderComponent = (
getUseSmartEdit: vi.fn(() => false),
getUseModelRouter: vi.fn(() => false),
getProxy: vi.fn(() => undefined),
isInteractive: vi.fn(() => false),
// --- Spread test-specific overrides ---
...contextValue,
@@ -219,6 +219,7 @@ describe('useGeminiStream', () => {
.mockReturnValue(contentGeneratorConfig),
getUseSmartEdit: () => false,
getUseModelRouter: () => false,
isInteractive: () => false,
} as unknown as Config;
mockOnDebugMessage = vi.fn();
mockHandleSlashCommand = vi.fn().mockResolvedValue(false);
@@ -80,6 +80,7 @@ const mockConfig = {
getEnableMessageBusIntegration: () => false,
getMessageBus: () => null,
getPolicyEngine: () => null,
isInteractive: () => false,
} as unknown as Config;
const mockTool = new MockTool({
+20 -17
View File
@@ -69,23 +69,6 @@ const mockContentGenerator = {
embedContent: mockEmbedContent,
} as unknown as Mocked<ContentGenerator>;
const mockConfig = {
getSessionId: vi.fn().mockReturnValue('test-session-id'),
getContentGeneratorConfig: vi
.fn()
.mockReturnValue({ authType: AuthType.USE_GEMINI }),
getEmbeddingModel: vi.fn().mockReturnValue('test-embedding-model'),
modelConfigService: {
getResolvedConfig: vi.fn().mockImplementation(({ model }) => ({
model,
generateContentConfig: {
temperature: 0,
topP: 1,
},
})),
},
} as unknown as Mocked<Config>;
// Helper to create a mock GenerateContentResponse
const createMockResponse = (text: string): GenerateContentResponse =>
({
@@ -96,6 +79,7 @@ describe('BaseLlmClient', () => {
let client: BaseLlmClient;
let abortController: AbortController;
let defaultOptions: GenerateJsonOptions;
let mockConfig: Mocked<Config>;
beforeEach(() => {
vi.clearAllMocks();
@@ -103,6 +87,25 @@ describe('BaseLlmClient', () => {
vi.mocked(getErrorMessage).mockImplementation((e) =>
e instanceof Error ? e.message : String(e),
);
mockConfig = {
getSessionId: vi.fn().mockReturnValue('test-session-id'),
getContentGeneratorConfig: vi
.fn()
.mockReturnValue({ authType: AuthType.USE_GEMINI }),
getEmbeddingModel: vi.fn().mockReturnValue('test-embedding-model'),
isInteractive: vi.fn().mockReturnValue(false),
modelConfigService: {
getResolvedConfig: vi.fn().mockImplementation(({ model }) => ({
model,
generateContentConfig: {
temperature: 0,
topP: 1,
},
})),
},
} as unknown as Mocked<Config>;
client = new BaseLlmClient(mockContentGenerator, mockConfig);
abortController = new AbortController();
defaultOptions = {
+3
View File
@@ -42,6 +42,7 @@ import { ideContextStore } from '../ide/ideContext.js';
import type { ModelRouterService } from '../routing/modelRouterService.js';
import { uiTelemetryService } from '../telemetry/uiTelemetry.js';
import { ChatCompressionService } from '../services/chatCompressionService.js';
import { ClearcutLogger } from '../telemetry/clearcut-logger/clearcut-logger.js';
vi.mock('../services/chatCompressionService.js');
@@ -174,6 +175,7 @@ describe('Gemini Client (client.ts)', () => {
let mockGenerateContentFn: Mock;
beforeEach(async () => {
vi.resetAllMocks();
ClearcutLogger.clearInstance();
vi.mocked(uiTelemetryService.setLastPromptTokenCount).mockClear();
vi.mocked(ChatCompressionService.prototype.compress).mockResolvedValue({
@@ -260,6 +262,7 @@ describe('Gemini Client (client.ts)', () => {
reasoning: 'test',
}),
}),
isInteractive: vi.fn().mockReturnValue(false),
} as unknown as Config;
client = new GeminiClient(mockConfig);
@@ -284,6 +284,7 @@ describe('CoreToolScheduler', () => {
const mockConfig = createMockConfig({
getToolRegistry: () => mockToolRegistry,
isInteractive: () => false,
});
const scheduler = new CoreToolScheduler({
@@ -349,6 +350,7 @@ describe('CoreToolScheduler', () => {
const mockConfig = createMockConfig({
getToolRegistry: () => mockToolRegistry,
isInteractive: () => false,
});
const scheduler = new CoreToolScheduler({
@@ -450,6 +452,7 @@ describe('CoreToolScheduler', () => {
const mockConfig = createMockConfig({
getToolRegistry: () => mockToolRegistry,
isInteractive: () => false,
});
const scheduler = new CoreToolScheduler({
@@ -546,6 +549,7 @@ describe('CoreToolScheduler', () => {
const mockConfig = createMockConfig({
getToolRegistry: () => mockToolRegistry,
isInteractive: () => false,
});
const scheduler = new CoreToolScheduler({
@@ -584,6 +588,7 @@ describe('CoreToolScheduler', () => {
} as unknown as ToolRegistry;
const mockConfig = createMockConfig({
getToolRegistry: () => mockToolRegistry,
isInteractive: () => false,
});
// Create scheduler
@@ -637,6 +642,7 @@ describe('CoreToolScheduler with payload', () => {
const mockConfig = createMockConfig({
getToolRegistry: () => mockToolRegistry,
isInteractive: () => false,
});
const scheduler = new CoreToolScheduler({
@@ -938,6 +944,7 @@ describe('CoreToolScheduler edit cancellation', () => {
const mockConfig = createMockConfig({
getToolRegistry: () => mockToolRegistry,
isInteractive: () => false,
});
const scheduler = new CoreToolScheduler({
@@ -1023,6 +1030,7 @@ describe('CoreToolScheduler YOLO mode', () => {
const mockConfig = createMockConfig({
getToolRegistry: () => mockToolRegistry,
getApprovalMode: () => ApprovalMode.YOLO,
isInteractive: () => false,
});
const scheduler = new CoreToolScheduler({
@@ -1109,6 +1117,7 @@ describe('CoreToolScheduler request queueing', () => {
const mockConfig = createMockConfig({
getToolRegistry: () => mockToolRegistry,
getApprovalMode: () => ApprovalMode.YOLO, // Use YOLO to avoid confirmation prompts
isInteractive: () => false,
});
const scheduler = new CoreToolScheduler({
@@ -1222,6 +1231,7 @@ describe('CoreToolScheduler request queueing', () => {
terminalWidth: 80,
terminalHeight: 24,
}),
isInteractive: () => false,
});
const scheduler = new CoreToolScheduler({
@@ -1329,6 +1339,7 @@ describe('CoreToolScheduler request queueing', () => {
terminalHeight: 24,
}),
getToolRegistry: () => toolRegistry,
isInteractive: () => false,
});
const scheduler = new CoreToolScheduler({
@@ -1385,6 +1396,7 @@ describe('CoreToolScheduler request queueing', () => {
const mockConfig = createMockConfig({
getToolRegistry: () => mockToolRegistry,
getApprovalMode: () => ApprovalMode.YOLO,
isInteractive: () => false,
});
const scheduler = new CoreToolScheduler({
@@ -1440,6 +1452,7 @@ describe('CoreToolScheduler request queueing', () => {
setApprovalMode: (mode: ApprovalMode) => {
approvalMode = mode;
},
isInteractive: () => false,
});
const testTool = new TestApprovalTool(mockConfig);
@@ -1611,6 +1624,7 @@ describe('CoreToolScheduler Sequential Execution', () => {
const mockConfig = createMockConfig({
getToolRegistry: () => mockToolRegistry,
getApprovalMode: () => ApprovalMode.YOLO, // Use YOLO to avoid confirmation prompts
isInteractive: () => false,
});
const scheduler = new CoreToolScheduler({
@@ -1710,6 +1724,7 @@ describe('CoreToolScheduler Sequential Execution', () => {
const mockConfig = createMockConfig({
getToolRegistry: () => mockToolRegistry,
getApprovalMode: () => ApprovalMode.YOLO,
isInteractive: () => false,
});
const scheduler = new CoreToolScheduler({
@@ -128,6 +128,7 @@ describe('GeminiChat', () => {
}),
getContentGenerator: vi.fn().mockReturnValue(mockContentGenerator),
getRetryFetchErrors: vi.fn().mockReturnValue(false),
isInteractive: vi.fn().mockReturnValue(false),
} as unknown as Config;
// Disable 429 simulation for tests
@@ -65,6 +65,7 @@ describe('executeToolCall', () => {
getEnableMessageBusIntegration: () => false,
getMessageBus: () => null,
getPolicyEngine: () => null,
isInteractive: () => false,
} as unknown as Config;
abortController = new AbortController();
@@ -40,6 +40,7 @@ const createMockConfig = (overrides: Partial<Config> = {}): Config =>
isInFallbackMode: vi.fn(() => false),
setFallbackMode: vi.fn(),
fallbackHandler: undefined,
isInteractive: vi.fn(() => false),
...overrides,
}) as unknown as Config;
@@ -117,6 +117,7 @@ describe('ChatCompressionService', () => {
mockConfig = {
getCompressionThreshold: vi.fn(),
getContentGenerator: vi.fn(),
isInteractive: vi.fn().mockReturnValue(false),
} as unknown as Config;
vi.mocked(tokenLimit).mockReturnValue(1000);
@@ -35,6 +35,7 @@ describe('LoopDetectionService', () => {
beforeEach(() => {
mockConfig = {
getTelemetryEnabled: () => true,
isInteractive: () => false,
} as unknown as Config;
service = new LoopDetectionService(mockConfig);
vi.clearAllMocks();
@@ -741,6 +742,7 @@ describe('LoopDetectionService LLM Checks', () => {
generateContentConfig: {},
}),
},
isInteractive: () => false,
} as unknown as Config;
service = new LoopDetectionService(mockConfig);
@@ -887,8 +887,7 @@ describe('ClearcutLogger', () => {
status: 'success',
} as SuccessfulToolCall;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
logger?.logToolCallEvent(new ToolCallEvent(completedToolCall as any));
logger?.logToolCallEvent(new ToolCallEvent(completedToolCall));
const events = getEvents(logger!);
expect(events.length).toBe(1);
@@ -933,8 +932,7 @@ describe('ClearcutLogger', () => {
status: 'success',
} as SuccessfulToolCall;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
logger?.logToolCallEvent(new ToolCallEvent(completedToolCall as any));
logger?.logToolCallEvent(new ToolCallEvent(completedToolCall));
const events = getEvents(logger!);
expect(events.length).toBe(1);
@@ -1301,6 +1301,10 @@ export class ClearcutLogger {
gemini_cli_key: EventMetadataKey.GEMINI_CLI_USER_SETTINGS,
value: this.getConfigJson(),
},
{
gemini_cli_key: EventMetadataKey.GEMINI_CLI_INTERACTIVE,
value: this.config?.isInteractive().toString() ?? 'false',
},
];
return [...data, ...defaultLogMetadata];
}
@@ -473,4 +473,7 @@ export enum EventMetadataKey {
// Logs whether the agent recovery attempt was successful.
GEMINI_CLI_AGENT_RECOVERY_SUCCESS = 124,
// Logs whether the session is interactive.
GEMINI_CLI_INTERACTIVE = 125,
}
@@ -69,7 +69,6 @@ describe('Circular Reference Handling', () => {
durationMs: 100,
};
// Create a tool call event with circular references in function_args
const event = new ToolCallEvent(mockCompletedToolCall);
// This should not throw an error
+54 -2
View File
@@ -211,6 +211,7 @@ describe('loggers', () => {
},
}),
}),
isInteractive: () => false,
} as unknown as Config;
const startSessionEvent = new StartSessionEvent(mockConfig);
@@ -224,6 +225,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_CLI_CONFIG,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
model: 'test-model',
embedding_model: 'test-embedding-model',
sandbox_enabled: true,
@@ -254,6 +256,7 @@ describe('loggers', () => {
getTelemetryEnabled: () => true,
getTelemetryLogPromptsEnabled: () => true,
getUsageStatisticsEnabled: () => true,
isInteractive: () => false,
} as unknown as Config;
it('should log a user prompt', () => {
@@ -274,6 +277,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_USER_PROMPT,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
prompt_length: 11,
prompt: 'test-prompt',
prompt_id: 'prompt-id-8',
@@ -289,6 +293,7 @@ describe('loggers', () => {
getTelemetryLogPromptsEnabled: () => false,
getTargetDir: () => 'target-dir',
getUsageStatisticsEnabled: () => true,
isInteractive: () => false,
} as unknown as Config;
const event = new UserPromptEvent(
11,
@@ -307,6 +312,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_USER_PROMPT,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
prompt_length: 11,
prompt_id: 'prompt-id-9',
auth_type: 'cloud-shell',
@@ -322,6 +328,7 @@ describe('loggers', () => {
getUsageStatisticsEnabled: () => true,
getTelemetryEnabled: () => true,
getTelemetryLogPromptsEnabled: () => true,
isInteractive: () => false,
} as Config;
const mockMetrics = {
@@ -496,6 +503,7 @@ describe('loggers', () => {
getUsageStatisticsEnabled: () => true,
getTelemetryEnabled: () => true,
getTelemetryLogPromptsEnabled: () => true,
isInteractive: () => false,
} as Config;
const mockMetrics = {
@@ -627,6 +635,7 @@ describe('loggers', () => {
getUsageStatisticsEnabled: () => true,
getTelemetryEnabled: () => true,
getTelemetryLogPromptsEnabled: () => true,
isInteractive: () => false,
} as Config;
it('should log an API request with request_text', () => {
@@ -646,6 +655,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_API_REQUEST,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
model: 'test-model',
request_text: 'This is a test request',
prompt_id: 'prompt-id-7',
@@ -666,6 +676,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_API_REQUEST,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
model: 'test-model',
prompt_id: 'prompt-id-6',
},
@@ -677,6 +688,7 @@ describe('loggers', () => {
const mockConfig = {
getSessionId: () => 'test-session-id',
getUsageStatisticsEnabled: () => true,
isInteractive: () => false,
} as unknown as Config;
it('should log flash fallback event', () => {
@@ -692,6 +704,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_FLASH_FALLBACK,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
auth_type: 'vertex-ai',
},
});
@@ -702,6 +715,7 @@ describe('loggers', () => {
const mockConfig = {
getSessionId: () => 'test-session-id',
getUsageStatisticsEnabled: () => true,
isInteractive: () => false,
} as unknown as Config;
beforeEach(() => {
@@ -794,6 +808,7 @@ describe('loggers', () => {
getUsageStatisticsEnabled: () => true,
getTelemetryEnabled: () => true,
getTelemetryLogPromptsEnabled: () => true,
isInteractive: () => false,
} as Config;
const mockMetrics = {
@@ -865,6 +880,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_TOOL_CALL,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
function_name: 'test-function',
function_args: JSON.stringify(
{
@@ -881,7 +897,8 @@ describe('loggers', () => {
tool_type: 'native',
error: undefined,
error_type: undefined,
mcp_server_name: undefined,
extension_id: undefined,
metadata: {
model_added_lines: 1,
model_removed_lines: 2,
@@ -962,6 +979,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_TOOL_CALL,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
function_name: 'test-function',
function_args: JSON.stringify(
{
@@ -978,6 +996,8 @@ describe('loggers', () => {
tool_type: 'native',
error: undefined,
error_type: undefined,
mcp_server_name: undefined,
extension_id: undefined,
metadata: undefined,
content_length: undefined,
},
@@ -1039,6 +1059,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_TOOL_CALL,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
function_name: 'test-function',
function_args: JSON.stringify(
{
@@ -1055,6 +1076,8 @@ describe('loggers', () => {
tool_type: 'native',
error: undefined,
error_type: undefined,
mcp_server_name: undefined,
extension_id: undefined,
metadata: undefined,
content_length: 13,
},
@@ -1115,6 +1138,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_TOOL_CALL,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
function_name: 'test-function',
function_args: JSON.stringify(
{
@@ -1131,6 +1155,8 @@ describe('loggers', () => {
decision: undefined,
error: undefined,
error_type: undefined,
mcp_server_name: undefined,
extension_id: undefined,
metadata: undefined,
content_length: 13,
},
@@ -1190,6 +1216,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_TOOL_CALL,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
function_name: 'test-function',
function_args: JSON.stringify(
{
@@ -1208,6 +1235,8 @@ describe('loggers', () => {
prompt_id: 'prompt-id-5',
tool_type: 'native',
decision: undefined,
mcp_server_name: undefined,
extension_id: undefined,
metadata: undefined,
content_length: errorMessage.length,
},
@@ -1273,7 +1302,6 @@ describe('loggers', () => {
durationMs: 100,
};
const event = new ToolCallEvent(call);
logToolCall(mockConfig, event);
expect(mockLogger.emit).toHaveBeenCalledWith({
@@ -1286,6 +1314,7 @@ describe('loggers', () => {
'event.timestamp': '2025-01-01T00:00:00.000Z',
extension_name: 'test-extension',
extension_id: 'test-extension-id',
interactive: false,
function_name: 'mock_mcp_tool',
function_args: JSON.stringify(
{
@@ -1333,6 +1362,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_MALFORMED_JSON_RESPONSE,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
model: 'test-model',
},
});
@@ -1346,6 +1376,7 @@ describe('loggers', () => {
getUsageStatisticsEnabled: () => true,
getTelemetryEnabled: () => true,
getTelemetryLogPromptsEnabled: () => true,
isInteractive: () => false,
} as Config;
const mockMetrics = {
@@ -1378,6 +1409,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_FILE_OPERATION,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
tool_name: 'test-tool',
operation: 'read',
lines: 10,
@@ -1404,6 +1436,7 @@ describe('loggers', () => {
const mockConfig = {
getSessionId: () => 'test-session-id',
getUsageStatisticsEnabled: () => true,
isInteractive: () => false,
} as unknown as Config;
it('should log a tool output truncated event', () => {
@@ -1426,6 +1459,7 @@ describe('loggers', () => {
'event.name': EVENT_TOOL_OUTPUT_TRUNCATED,
'event.timestamp': '2025-01-01T00:00:00.000Z',
eventName: 'tool_output_truncated',
interactive: false,
prompt_id: 'prompt-id-1',
tool_name: 'test-tool',
original_content_length: 1000,
@@ -1441,6 +1475,7 @@ describe('loggers', () => {
const mockConfig = {
getSessionId: () => 'test-session-id',
getUsageStatisticsEnabled: () => true,
isInteractive: () => false,
} as unknown as Config;
beforeEach(() => {
@@ -1472,6 +1507,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
...event,
'event.name': EVENT_MODEL_ROUTING,
interactive: false,
},
});
@@ -1509,6 +1545,7 @@ describe('loggers', () => {
getContentGeneratorConfig: () => null,
getUseSmartEdit: () => null,
getUseModelRouter: () => null,
isInteractive: () => false,
} as unknown as Config;
beforeEach(() => {
@@ -1542,6 +1579,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_EXTENSION_INSTALL,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
extension_name: 'testing',
extension_version: '0.1.0',
extension_source: 'git',
@@ -1558,6 +1596,7 @@ describe('loggers', () => {
getContentGeneratorConfig: () => null,
getUseSmartEdit: () => null,
getUseModelRouter: () => null,
isInteractive: () => false,
} as unknown as Config;
beforeEach(() => {
@@ -1592,6 +1631,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_EXTENSION_UPDATE,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
extension_name: 'testing',
extension_version: '0.1.0',
extension_previous_version: '0.1.1',
@@ -1609,6 +1649,7 @@ describe('loggers', () => {
getContentGeneratorConfig: () => null,
getUseSmartEdit: () => null,
getUseModelRouter: () => null,
isInteractive: () => false,
} as unknown as Config;
beforeEach(() => {
@@ -1639,6 +1680,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_EXTENSION_UNINSTALL,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
extension_name: 'testing',
status: 'success',
},
@@ -1650,6 +1692,7 @@ describe('loggers', () => {
const mockConfig = {
getSessionId: () => 'test-session-id',
getUsageStatisticsEnabled: () => true,
isInteractive: () => false,
} as unknown as Config;
beforeEach(() => {
@@ -1677,6 +1720,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_EXTENSION_ENABLE,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
extension_name: 'testing',
setting_scope: 'user',
},
@@ -1688,6 +1732,7 @@ describe('loggers', () => {
const mockConfig = {
getSessionId: () => 'test-session-id',
getUsageStatisticsEnabled: () => true,
isInteractive: () => false,
} as unknown as Config;
beforeEach(() => {
@@ -1715,6 +1760,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_EXTENSION_DISABLE,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
extension_name: 'testing',
setting_scope: 'user',
},
@@ -1726,6 +1772,7 @@ describe('loggers', () => {
const mockConfig = {
getSessionId: () => 'test-session-id',
getUsageStatisticsEnabled: () => true,
isInteractive: () => false,
} as unknown as Config;
beforeEach(() => {
@@ -1749,6 +1796,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_AGENT_START,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
agent_id: 'agent-123',
agent_name: 'TestAgent',
},
@@ -1760,6 +1808,7 @@ describe('loggers', () => {
const mockConfig = {
getSessionId: () => 'test-session-id',
getUsageStatisticsEnabled: () => true,
isInteractive: () => false,
} as unknown as Config;
beforeEach(() => {
@@ -1790,6 +1839,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_AGENT_FINISH,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
agent_id: 'agent-123',
agent_name: 'TestAgent',
duration_ms: 1000,
@@ -1809,6 +1859,7 @@ describe('loggers', () => {
const mockConfig = {
getSessionId: () => 'test-session-id',
getUsageStatisticsEnabled: () => true,
isInteractive: () => false,
} as unknown as Config;
beforeEach(() => {
@@ -1832,6 +1883,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_WEB_FETCH_FALLBACK_ATTEMPT,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
reason: 'private_ip',
},
});
@@ -17,6 +17,7 @@ export function getCommonAttributes(config: Config): Attributes {
return {
'session.id': config.getSessionId(),
'installation.id': installationManager.getInstallationId(),
interactive: config.isInteractive(),
...(email && { 'user.email': email }),
};
}
+14 -1
View File
@@ -161,6 +161,19 @@ export class EndSessionEvent implements BaseTelemetryEvent {
this['event.timestamp'] = new Date().toISOString();
this.session_id = config?.getSessionId();
}
toOpenTelemetryAttributes(config: Config): LogAttributes {
return {
...getCommonAttributes(config),
'event.name': this['event.name'],
'event.timestamp': this['event.timestamp'],
session_id: this.session_id,
};
}
toLogBody(): string {
return 'Session ended.';
}
}
export const EVENT_USER_PROMPT = 'gemini_cli.user_prompt';
@@ -299,7 +312,7 @@ export class ToolCallEvent implements BaseTelemetryEvent {
}
}
} else {
this.function_name = function_name!;
this.function_name = function_name as string;
this.function_args = function_args!;
this.duration_ms = duration_ms!;
this.success = success!;
+1
View File
@@ -110,6 +110,7 @@ describe('EditTool', () => {
getGeminiMdFileCount: () => 0,
setGeminiMdFileCount: vi.fn(),
getToolRegistry: () => ({}) as any, // Minimal mock for ToolRegistry
isInteractive: () => false,
} as unknown as Config;
// Reset mocks before each test
@@ -45,6 +45,7 @@ describe('ReadFileTool', () => {
storage: {
getProjectTempDir: () => path.join(tempRootDir, '.temp'),
},
isInteractive: () => false,
} as unknown as Config;
tool = new ReadFileTool(mockConfigInstance);
});
@@ -88,6 +88,7 @@ describe('ReadManyFilesTool', () => {
buildExcludePatterns: () => DEFAULT_FILE_EXCLUDES,
getReadManyFilesExcludes: () => DEFAULT_FILE_EXCLUDES,
}),
isInteractive: () => false,
} as Partial<Config> as Config;
tool = new ReadManyFilesTool(mockConfig);
@@ -502,6 +503,7 @@ describe('ReadManyFilesTool', () => {
buildExcludePatterns: () => [],
getReadManyFilesExcludes: () => [],
}),
isInteractive: () => false,
} as Partial<Config> as Config;
tool = new ReadManyFilesTool(mockConfig);
@@ -117,6 +117,7 @@ describe('SmartEditTool', () => {
getGeminiMdFileCount: () => 0,
setGeminiMdFileCount: vi.fn(),
getToolRegistry: () => ({}) as any,
isInteractive: () => false,
} as unknown as Config;
(mockConfig.getApprovalMode as Mock).mockClear();
@@ -142,6 +142,7 @@ describe('WebFetchTool', () => {
setApprovalMode: vi.fn(),
getProxy: vi.fn(),
getGeminiClient: mockGetGeminiClient,
isInteractive: () => false,
} as unknown as Config;
});
@@ -96,6 +96,7 @@ const mockConfigInternal = {
registerTool: vi.fn(),
discoverTools: vi.fn(),
}) as unknown as ToolRegistry,
isInteractive: () => false,
};
const mockConfig = mockConfigInternal as unknown as Config;