mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-22 02:54:31 -07:00
Code assist service metrics. (#15024)
This commit is contained in:
committed by
GitHub
parent
5ea5107d05
commit
5e21c8c03c
@@ -0,0 +1,162 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import {
|
||||
createConversationOffered,
|
||||
formatProtoJsonDuration,
|
||||
} from './telemetry.js';
|
||||
import { ActionStatus, type StreamingLatency } from './types.js';
|
||||
import { FinishReason, GenerateContentResponse } from '@google/genai';
|
||||
|
||||
function createMockResponse(
|
||||
candidates: GenerateContentResponse['candidates'] = [],
|
||||
ok = true,
|
||||
) {
|
||||
const response = new GenerateContentResponse();
|
||||
response.candidates = candidates;
|
||||
response.sdkHttpResponse = {
|
||||
responseInternal: {
|
||||
ok,
|
||||
} as unknown as Response,
|
||||
json: async () => ({}),
|
||||
};
|
||||
return response;
|
||||
}
|
||||
|
||||
describe('telemetry', () => {
|
||||
describe('createConversationOffered', () => {
|
||||
it('should create a ConversationOffered object with correct values', () => {
|
||||
const response = createMockResponse([
|
||||
{
|
||||
index: 0,
|
||||
content: {
|
||||
role: 'model',
|
||||
parts: [{ text: 'response with ```code```' }],
|
||||
},
|
||||
citationMetadata: {
|
||||
citations: [
|
||||
{ uri: 'https://example.com', startIndex: 0, endIndex: 10 },
|
||||
],
|
||||
},
|
||||
finishReason: FinishReason.STOP,
|
||||
},
|
||||
]);
|
||||
const traceId = 'test-trace-id';
|
||||
const streamingLatency: StreamingLatency = { totalLatency: '1s' };
|
||||
|
||||
const result = createConversationOffered(
|
||||
response,
|
||||
traceId,
|
||||
undefined,
|
||||
streamingLatency,
|
||||
);
|
||||
|
||||
expect(result).toEqual({
|
||||
citationCount: '1',
|
||||
includedCode: true,
|
||||
status: ActionStatus.ACTION_STATUS_NO_ERROR,
|
||||
traceId,
|
||||
streamingLatency,
|
||||
isAgentic: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('should set status to CANCELLED if signal is aborted', () => {
|
||||
const response = createMockResponse();
|
||||
const signal = new AbortController().signal;
|
||||
vi.spyOn(signal, 'aborted', 'get').mockReturnValue(true);
|
||||
|
||||
const result = createConversationOffered(
|
||||
response,
|
||||
'trace-id',
|
||||
signal,
|
||||
{},
|
||||
);
|
||||
|
||||
expect(result.status).toBe(ActionStatus.ACTION_STATUS_CANCELLED);
|
||||
});
|
||||
|
||||
it('should set status to ERROR_UNKNOWN if response has error (non-OK SDK response)', () => {
|
||||
const response = createMockResponse([], false);
|
||||
|
||||
const result = createConversationOffered(
|
||||
response,
|
||||
'trace-id',
|
||||
undefined,
|
||||
{},
|
||||
);
|
||||
|
||||
expect(result.status).toBe(ActionStatus.ACTION_STATUS_ERROR_UNKNOWN);
|
||||
});
|
||||
|
||||
it('should set status to ERROR_UNKNOWN if finishReason is not STOP or MAX_TOKENS', () => {
|
||||
const response = createMockResponse([
|
||||
{
|
||||
index: 0,
|
||||
finishReason: FinishReason.SAFETY,
|
||||
},
|
||||
]);
|
||||
|
||||
const result = createConversationOffered(
|
||||
response,
|
||||
'trace-id',
|
||||
undefined,
|
||||
{},
|
||||
);
|
||||
|
||||
expect(result.status).toBe(ActionStatus.ACTION_STATUS_ERROR_UNKNOWN);
|
||||
});
|
||||
|
||||
it('should set status to EMPTY if candidates is empty', () => {
|
||||
const response = createMockResponse();
|
||||
|
||||
const result = createConversationOffered(
|
||||
response,
|
||||
'trace-id',
|
||||
undefined,
|
||||
{},
|
||||
);
|
||||
|
||||
expect(result.status).toBe(ActionStatus.ACTION_STATUS_EMPTY);
|
||||
});
|
||||
|
||||
it('should detect code in response', () => {
|
||||
const response = createMockResponse([
|
||||
{
|
||||
index: 0,
|
||||
content: {
|
||||
parts: [
|
||||
{ text: 'Here is some code:\n```js\nconsole.log("hi")\n```' },
|
||||
],
|
||||
},
|
||||
},
|
||||
]);
|
||||
const result = createConversationOffered(response, 'id', undefined, {});
|
||||
expect(result.includedCode).toBe(true);
|
||||
});
|
||||
|
||||
it('should not detect code if no backticks', () => {
|
||||
const response = createMockResponse([
|
||||
{
|
||||
index: 0,
|
||||
content: {
|
||||
parts: [{ text: 'Here is some text.' }],
|
||||
},
|
||||
},
|
||||
]);
|
||||
const result = createConversationOffered(response, 'id', undefined, {});
|
||||
expect(result.includedCode).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('formatProtoJsonDuration', () => {
|
||||
it('should format milliseconds to seconds string', () => {
|
||||
expect(formatProtoJsonDuration(1500)).toBe('1.5s');
|
||||
expect(formatProtoJsonDuration(100)).toBe('0.1s');
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user