diff options
| author | Arya Gummadi <[email protected]> | 2025-08-18 22:57:53 -0700 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-08-19 05:57:53 +0000 |
| commit | 8f8082fe3da9e1972f8b8226c68fa14e326a3d8a (patch) | |
| tree | f4e8b121bea73120e57e59eba8d6ad3fbda2c59c /packages/core/src | |
| parent | da396bd5662adcac3ebc60d55cfc1d722b903e38 (diff) | |
feat: add file change tracking to session metrics (#6094)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: Jacob Richman <[email protected]>
Diffstat (limited to 'packages/core/src')
| -rw-r--r-- | packages/core/src/telemetry/uiTelemetry.test.ts | 74 | ||||
| -rw-r--r-- | packages/core/src/telemetry/uiTelemetry.ts | 20 |
2 files changed, 77 insertions, 17 deletions
diff --git a/packages/core/src/telemetry/uiTelemetry.test.ts b/packages/core/src/telemetry/uiTelemetry.test.ts index cd509a8e..a64f839e 100644 --- a/packages/core/src/telemetry/uiTelemetry.test.ts +++ b/packages/core/src/telemetry/uiTelemetry.test.ts @@ -108,6 +108,10 @@ describe('UiTelemetryService', () => { }, byName: {}, }, + files: { + totalLinesAdded: 0, + totalLinesRemoved: 0, + }, }); expect(service.getLastPromptTokenCount()).toBe(0); }); @@ -342,9 +346,9 @@ describe('UiTelemetryService', () => { ToolConfirmationOutcome.ProceedOnce, ); service.addEvent({ - ...JSON.parse(JSON.stringify(new ToolCallEvent(toolCall))), + ...structuredClone(new ToolCallEvent(toolCall)), 'event.name': EVENT_TOOL_CALL, - }); + } as ToolCallEvent & { 'event.name': typeof EVENT_TOOL_CALL }); const metrics = service.getMetrics(); const { tools } = metrics; @@ -376,9 +380,9 @@ describe('UiTelemetryService', () => { ToolConfirmationOutcome.Cancel, ); service.addEvent({ - ...JSON.parse(JSON.stringify(new ToolCallEvent(toolCall))), + ...structuredClone(new ToolCallEvent(toolCall)), 'event.name': EVENT_TOOL_CALL, - }); + } as ToolCallEvent & { 'event.name': typeof EVENT_TOOL_CALL }); const metrics = service.getMetrics(); const { tools } = metrics; @@ -410,9 +414,9 @@ describe('UiTelemetryService', () => { ToolConfirmationOutcome.ModifyWithEditor, ); service.addEvent({ - ...JSON.parse(JSON.stringify(new ToolCallEvent(toolCall))), + ...structuredClone(new ToolCallEvent(toolCall)), 'event.name': EVENT_TOOL_CALL, - }); + } as ToolCallEvent & { 'event.name': typeof EVENT_TOOL_CALL }); const metrics = service.getMetrics(); const { tools } = metrics; @@ -426,9 +430,9 @@ describe('UiTelemetryService', () => { it('should process a ToolCallEvent without a decision', () => { const toolCall = createFakeCompletedToolCall('test_tool', true, 100); service.addEvent({ - ...JSON.parse(JSON.stringify(new ToolCallEvent(toolCall))), + ...structuredClone(new ToolCallEvent(toolCall)), 'event.name': EVENT_TOOL_CALL, - }); + } as ToolCallEvent & { 'event.name': typeof EVENT_TOOL_CALL }); const metrics = service.getMetrics(); const { tools } = metrics; @@ -462,13 +466,13 @@ describe('UiTelemetryService', () => { ); service.addEvent({ - ...JSON.parse(JSON.stringify(new ToolCallEvent(toolCall1))), + ...structuredClone(new ToolCallEvent(toolCall1)), 'event.name': EVENT_TOOL_CALL, - }); + } as ToolCallEvent & { 'event.name': typeof EVENT_TOOL_CALL }); service.addEvent({ - ...JSON.parse(JSON.stringify(new ToolCallEvent(toolCall2))), + ...structuredClone(new ToolCallEvent(toolCall2)), 'event.name': EVENT_TOOL_CALL, - }); + } as ToolCallEvent & { 'event.name': typeof EVENT_TOOL_CALL }); const metrics = service.getMetrics(); const { tools } = metrics; @@ -497,13 +501,13 @@ describe('UiTelemetryService', () => { const toolCall1 = createFakeCompletedToolCall('tool_A', true, 100); const toolCall2 = createFakeCompletedToolCall('tool_B', false, 200); service.addEvent({ - ...JSON.parse(JSON.stringify(new ToolCallEvent(toolCall1))), + ...structuredClone(new ToolCallEvent(toolCall1)), 'event.name': EVENT_TOOL_CALL, - }); + } as ToolCallEvent & { 'event.name': typeof EVENT_TOOL_CALL }); service.addEvent({ - ...JSON.parse(JSON.stringify(new ToolCallEvent(toolCall2))), + ...structuredClone(new ToolCallEvent(toolCall2)), 'event.name': EVENT_TOOL_CALL, - }); + } as ToolCallEvent & { 'event.name': typeof EVENT_TOOL_CALL }); const metrics = service.getMetrics(); const { tools } = metrics; @@ -629,4 +633,42 @@ describe('UiTelemetryService', () => { expect(spy).toHaveBeenCalledOnce(); }); }); + + describe('Tool Call Event with Line Count Metadata', () => { + it('should aggregate valid line count metadata', () => { + const toolCall = createFakeCompletedToolCall('test_tool', true, 100); + const event = { + ...structuredClone(new ToolCallEvent(toolCall)), + 'event.name': EVENT_TOOL_CALL, + metadata: { + ai_added_lines: 10, + ai_removed_lines: 5, + }, + } as ToolCallEvent & { 'event.name': typeof EVENT_TOOL_CALL }; + + service.addEvent(event); + + const metrics = service.getMetrics(); + expect(metrics.files.totalLinesAdded).toBe(10); + expect(metrics.files.totalLinesRemoved).toBe(5); + }); + + it('should ignore null/undefined values in line count metadata', () => { + const toolCall = createFakeCompletedToolCall('test_tool', true, 100); + const event = { + ...structuredClone(new ToolCallEvent(toolCall)), + 'event.name': EVENT_TOOL_CALL, + metadata: { + ai_added_lines: null, + ai_removed_lines: undefined, + }, + } as ToolCallEvent & { 'event.name': typeof EVENT_TOOL_CALL }; + + service.addEvent(event); + + const metrics = service.getMetrics(); + expect(metrics.files.totalLinesAdded).toBe(0); + expect(metrics.files.totalLinesRemoved).toBe(0); + }); + }); }); diff --git a/packages/core/src/telemetry/uiTelemetry.ts b/packages/core/src/telemetry/uiTelemetry.ts index 8d1b044f..318478aa 100644 --- a/packages/core/src/telemetry/uiTelemetry.ts +++ b/packages/core/src/telemetry/uiTelemetry.ts @@ -63,6 +63,10 @@ export interface SessionMetrics { }; byName: Record<string, ToolCallStats>; }; + files: { + totalLinesAdded: number; + totalLinesRemoved: number; + }; } const createInitialModelMetrics = (): ModelMetrics => ({ @@ -96,6 +100,10 @@ const createInitialMetrics = (): SessionMetrics => ({ }, byName: {}, }, + files: { + totalLinesAdded: 0, + totalLinesRemoved: 0, + }, }); export class UiTelemetryService extends EventEmitter { @@ -171,7 +179,7 @@ export class UiTelemetryService extends EventEmitter { } private processToolCall(event: ToolCallEvent) { - const { tools } = this.#metrics; + const { tools, files } = this.#metrics; tools.totalCalls++; tools.totalDurationMs += event.duration_ms; @@ -209,6 +217,16 @@ export class UiTelemetryService extends EventEmitter { tools.totalDecisions[event.decision]++; toolStats.decisions[event.decision]++; } + + // Aggregate line count data from metadata + if (event.metadata) { + if (event.metadata['ai_added_lines'] !== undefined) { + files.totalLinesAdded += event.metadata['ai_added_lines']; + } + if (event.metadata['ai_removed_lines'] !== undefined) { + files.totalLinesRemoved += event.metadata['ai_removed_lines']; + } + } } } |
