mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-20 18:14:29 -07:00
telemetry: track interactive session state (#12856)
Co-authored-by: owenofbrien <86964623+owenofbrien@users.noreply.github.com>
This commit is contained in:
@@ -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({
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 }),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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!;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user