mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-19 09:33:53 +00:00
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 <jacob314@gmail.com>
This commit is contained in:
@@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user