mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-19 09:33:53 +00:00
Log yolo mode + number of turns (#6055)
Co-authored-by: Shi Shu <shii@google.com>
This commit is contained in:
@@ -26,6 +26,7 @@ import {
|
|||||||
TrackedCancelledToolCall,
|
TrackedCancelledToolCall,
|
||||||
} from './useReactToolScheduler.js';
|
} from './useReactToolScheduler.js';
|
||||||
import {
|
import {
|
||||||
|
ApprovalMode,
|
||||||
Config,
|
Config,
|
||||||
EditorType,
|
EditorType,
|
||||||
AuthType,
|
AuthType,
|
||||||
@@ -194,6 +195,7 @@ describe('useGeminiStream', () => {
|
|||||||
getProjectRoot: vi.fn(() => '/test/dir'),
|
getProjectRoot: vi.fn(() => '/test/dir'),
|
||||||
getCheckpointingEnabled: vi.fn(() => false),
|
getCheckpointingEnabled: vi.fn(() => false),
|
||||||
getGeminiClient: mockGetGeminiClient,
|
getGeminiClient: mockGetGeminiClient,
|
||||||
|
getApprovalMode: () => ApprovalMode.DEFAULT,
|
||||||
getUsageStatisticsEnabled: () => true,
|
getUsageStatisticsEnabled: () => true,
|
||||||
getDebugMode: () => false,
|
getDebugMode: () => false,
|
||||||
addHistory: vi.fn(),
|
addHistory: vi.fn(),
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ import {
|
|||||||
UnauthorizedError,
|
UnauthorizedError,
|
||||||
UserPromptEvent,
|
UserPromptEvent,
|
||||||
DEFAULT_GEMINI_FLASH_MODEL,
|
DEFAULT_GEMINI_FLASH_MODEL,
|
||||||
|
logConversationFinishedEvent,
|
||||||
|
ConversationFinishedEvent,
|
||||||
|
ApprovalMode,
|
||||||
parseAndFormatApiError,
|
parseAndFormatApiError,
|
||||||
} from '@google/gemini-cli-core';
|
} from '@google/gemini-cli-core';
|
||||||
import { type Part, type PartListUnion, FinishReason } from '@google/genai';
|
import { type Part, type PartListUnion, FinishReason } from '@google/genai';
|
||||||
@@ -172,6 +175,27 @@ export const useGeminiStream = (
|
|||||||
return StreamingState.Idle;
|
return StreamingState.Idle;
|
||||||
}, [isResponding, toolCalls]);
|
}, [isResponding, toolCalls]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (
|
||||||
|
config.getApprovalMode() === ApprovalMode.YOLO &&
|
||||||
|
streamingState === StreamingState.Idle
|
||||||
|
) {
|
||||||
|
const lastUserMessageIndex = history.findLastIndex(
|
||||||
|
(item: HistoryItem) => item.type === MessageType.USER,
|
||||||
|
);
|
||||||
|
|
||||||
|
const turnCount =
|
||||||
|
lastUserMessageIndex === -1 ? 0 : history.length - lastUserMessageIndex;
|
||||||
|
|
||||||
|
if (turnCount > 0) {
|
||||||
|
logConversationFinishedEvent(
|
||||||
|
config,
|
||||||
|
new ConversationFinishedEvent(config.getApprovalMode(), turnCount),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [streamingState, config, history]);
|
||||||
|
|
||||||
const cancelOngoingRequest = useCallback(() => {
|
const cancelOngoingRequest = useCallback(() => {
|
||||||
if (streamingState !== StreamingState.Responding) {
|
if (streamingState !== StreamingState.Responding) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "dist",
|
"outDir": "dist",
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
"lib": ["DOM", "DOM.Iterable", "ES2022"],
|
"lib": ["DOM", "DOM.Iterable", "ES2023"],
|
||||||
"types": ["node", "vitest/globals"]
|
"types": ["node", "vitest/globals"]
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import {
|
|||||||
SlashCommandEvent,
|
SlashCommandEvent,
|
||||||
MalformedJsonResponseEvent,
|
MalformedJsonResponseEvent,
|
||||||
IdeConnectionEvent,
|
IdeConnectionEvent,
|
||||||
|
ConversationFinishedEvent,
|
||||||
KittySequenceOverflowEvent,
|
KittySequenceOverflowEvent,
|
||||||
ChatCompressionEvent,
|
ChatCompressionEvent,
|
||||||
FileOperationEvent,
|
FileOperationEvent,
|
||||||
@@ -47,6 +48,7 @@ export enum EventNames {
|
|||||||
IDE_CONNECTION = 'ide_connection',
|
IDE_CONNECTION = 'ide_connection',
|
||||||
KITTY_SEQUENCE_OVERFLOW = 'kitty_sequence_overflow',
|
KITTY_SEQUENCE_OVERFLOW = 'kitty_sequence_overflow',
|
||||||
CHAT_COMPRESSION = 'chat_compression',
|
CHAT_COMPRESSION = 'chat_compression',
|
||||||
|
CONVERSATION_FINISHED = 'conversation_finished',
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LogResponse {
|
export interface LogResponse {
|
||||||
@@ -728,6 +730,28 @@ export class ClearcutLogger {
|
|||||||
this.flushIfNeeded();
|
this.flushIfNeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logConversationFinishedEvent(event: ConversationFinishedEvent): void {
|
||||||
|
const data: EventValue[] = [
|
||||||
|
{
|
||||||
|
gemini_cli_key: EventMetadataKey.GEMINI_CLI_SESSION_ID,
|
||||||
|
value: this.config?.getSessionId() ?? '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
gemini_cli_key: EventMetadataKey.GEMINI_CLI_CONVERSATION_TURN_COUNT,
|
||||||
|
value: JSON.stringify(event.turnCount),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
gemini_cli_key: EventMetadataKey.GEMINI_CLI_APPROVAL_MODE,
|
||||||
|
value: event.approvalMode,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
this.enqueueLogEvent(
|
||||||
|
this.createLogEvent(EventNames.CONVERSATION_FINISHED, data),
|
||||||
|
);
|
||||||
|
this.flushIfNeeded();
|
||||||
|
}
|
||||||
|
|
||||||
logKittySequenceOverflowEvent(event: KittySequenceOverflowEvent): void {
|
logKittySequenceOverflowEvent(event: KittySequenceOverflowEvent): void {
|
||||||
const data: EventValue[] = [
|
const data: EventValue[] = [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -232,6 +232,16 @@ export enum EventMetadataKey {
|
|||||||
// Logs the length of the kitty sequence that overflowed.
|
// Logs the length of the kitty sequence that overflowed.
|
||||||
GEMINI_CLI_KITTY_SEQUENCE_LENGTH = 53,
|
GEMINI_CLI_KITTY_SEQUENCE_LENGTH = 53,
|
||||||
|
|
||||||
|
// ==========================================================================
|
||||||
|
// Conversation Finished Event Keys
|
||||||
|
// ===========================================================================
|
||||||
|
|
||||||
|
// Logs the approval mode
|
||||||
|
GEMINI_CLI_APPROVAL_MODE = 70,
|
||||||
|
|
||||||
|
// Logs the number of turns
|
||||||
|
GEMINI_CLI_CONVERSATION_TURN_COUNT = 71,
|
||||||
|
|
||||||
// Logs the number of tokens before context window compression.
|
// Logs the number of tokens before context window compression.
|
||||||
GEMINI_CLI_COMPRESSION_TOKENS_BEFORE = 60,
|
GEMINI_CLI_COMPRESSION_TOKENS_BEFORE = 60,
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ export const EVENT_FLASH_FALLBACK = 'gemini_cli.flash_fallback';
|
|||||||
export const EVENT_NEXT_SPEAKER_CHECK = 'gemini_cli.next_speaker_check';
|
export const EVENT_NEXT_SPEAKER_CHECK = 'gemini_cli.next_speaker_check';
|
||||||
export const EVENT_SLASH_COMMAND = 'gemini_cli.slash_command';
|
export const EVENT_SLASH_COMMAND = 'gemini_cli.slash_command';
|
||||||
export const EVENT_IDE_CONNECTION = 'gemini_cli.ide_connection';
|
export const EVENT_IDE_CONNECTION = 'gemini_cli.ide_connection';
|
||||||
|
export const EVENT_CONVERSATION_FINISHED = 'gemini_cli.conversation_finished';
|
||||||
export const EVENT_CHAT_COMPRESSION = 'gemini_cli.chat_compression';
|
export const EVENT_CHAT_COMPRESSION = 'gemini_cli.chat_compression';
|
||||||
export const EVENT_MALFORMED_JSON_RESPONSE =
|
export const EVENT_MALFORMED_JSON_RESPONSE =
|
||||||
'gemini_cli.malformed_json_response';
|
'gemini_cli.malformed_json_response';
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ export {
|
|||||||
logApiResponse,
|
logApiResponse,
|
||||||
logFlashFallback,
|
logFlashFallback,
|
||||||
logSlashCommand,
|
logSlashCommand,
|
||||||
|
logConversationFinishedEvent,
|
||||||
logKittySequenceOverflow,
|
logKittySequenceOverflow,
|
||||||
logChatCompression,
|
logChatCompression,
|
||||||
} from './loggers.js';
|
} from './loggers.js';
|
||||||
@@ -40,6 +41,7 @@ export {
|
|||||||
ApiResponseEvent,
|
ApiResponseEvent,
|
||||||
TelemetryEvent,
|
TelemetryEvent,
|
||||||
FlashFallbackEvent,
|
FlashFallbackEvent,
|
||||||
|
ConversationFinishedEvent,
|
||||||
KittySequenceOverflowEvent,
|
KittySequenceOverflowEvent,
|
||||||
SlashCommandEvent,
|
SlashCommandEvent,
|
||||||
makeSlashCommandEvent,
|
makeSlashCommandEvent,
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import {
|
|||||||
EVENT_NEXT_SPEAKER_CHECK,
|
EVENT_NEXT_SPEAKER_CHECK,
|
||||||
SERVICE_NAME,
|
SERVICE_NAME,
|
||||||
EVENT_SLASH_COMMAND,
|
EVENT_SLASH_COMMAND,
|
||||||
|
EVENT_CONVERSATION_FINISHED,
|
||||||
EVENT_CHAT_COMPRESSION,
|
EVENT_CHAT_COMPRESSION,
|
||||||
EVENT_MALFORMED_JSON_RESPONSE,
|
EVENT_MALFORMED_JSON_RESPONSE,
|
||||||
} from './constants.js';
|
} from './constants.js';
|
||||||
@@ -35,6 +36,7 @@ import {
|
|||||||
NextSpeakerCheckEvent,
|
NextSpeakerCheckEvent,
|
||||||
LoopDetectedEvent,
|
LoopDetectedEvent,
|
||||||
SlashCommandEvent,
|
SlashCommandEvent,
|
||||||
|
ConversationFinishedEvent,
|
||||||
KittySequenceOverflowEvent,
|
KittySequenceOverflowEvent,
|
||||||
ChatCompressionEvent,
|
ChatCompressionEvent,
|
||||||
MalformedJsonResponseEvent,
|
MalformedJsonResponseEvent,
|
||||||
@@ -409,6 +411,27 @@ export function logIdeConnection(
|
|||||||
logger.emit(logRecord);
|
logger.emit(logRecord);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function logConversationFinishedEvent(
|
||||||
|
config: Config,
|
||||||
|
event: ConversationFinishedEvent,
|
||||||
|
): void {
|
||||||
|
ClearcutLogger.getInstance(config)?.logConversationFinishedEvent(event);
|
||||||
|
if (!isTelemetrySdkInitialized()) return;
|
||||||
|
|
||||||
|
const attributes: LogAttributes = {
|
||||||
|
...getCommonAttributes(config),
|
||||||
|
...event,
|
||||||
|
'event.name': EVENT_CONVERSATION_FINISHED,
|
||||||
|
};
|
||||||
|
|
||||||
|
const logger = logs.getLogger(SERVICE_NAME);
|
||||||
|
const logRecord: LogRecord = {
|
||||||
|
body: `Conversation finished.`,
|
||||||
|
attributes,
|
||||||
|
};
|
||||||
|
logger.emit(logRecord);
|
||||||
|
}
|
||||||
|
|
||||||
export function logChatCompression(
|
export function logChatCompression(
|
||||||
config: Config,
|
config: Config,
|
||||||
event: ChatCompressionEvent,
|
event: ChatCompressionEvent,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { GenerateContentResponseUsageMetadata } from '@google/genai';
|
import { GenerateContentResponseUsageMetadata } from '@google/genai';
|
||||||
import { Config } from '../config/config.js';
|
import { ApprovalMode, Config } from '../config/config.js';
|
||||||
import { CompletedToolCall } from '../core/coreToolScheduler.js';
|
import { CompletedToolCall } from '../core/coreToolScheduler.js';
|
||||||
import { DiscoveredMCPTool } from '../tools/mcp-tool.js';
|
import { DiscoveredMCPTool } from '../tools/mcp-tool.js';
|
||||||
import { DiffStat, FileDiff } from '../tools/tools.js';
|
import { DiffStat, FileDiff } from '../tools/tools.js';
|
||||||
@@ -387,6 +387,20 @@ export class IdeConnectionEvent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class ConversationFinishedEvent {
|
||||||
|
'event_name': 'conversation_finished';
|
||||||
|
'event.timestamp': string; // ISO 8601;
|
||||||
|
approvalMode: ApprovalMode;
|
||||||
|
turnCount: number;
|
||||||
|
|
||||||
|
constructor(approvalMode: ApprovalMode, turnCount: number) {
|
||||||
|
this['event_name'] = 'conversation_finished';
|
||||||
|
this['event.timestamp'] = new Date().toISOString();
|
||||||
|
this.approvalMode = approvalMode;
|
||||||
|
this.turnCount = turnCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class KittySequenceOverflowEvent {
|
export class KittySequenceOverflowEvent {
|
||||||
'event.name': 'kitty_sequence_overflow';
|
'event.name': 'kitty_sequence_overflow';
|
||||||
'event.timestamp': string; // ISO 8601
|
'event.timestamp': string; // ISO 8601
|
||||||
@@ -447,5 +461,6 @@ export type TelemetryEvent =
|
|||||||
| KittySequenceOverflowEvent
|
| KittySequenceOverflowEvent
|
||||||
| MalformedJsonResponseEvent
|
| MalformedJsonResponseEvent
|
||||||
| IdeConnectionEvent
|
| IdeConnectionEvent
|
||||||
|
| ConversationFinishedEvent
|
||||||
| SlashCommandEvent
|
| SlashCommandEvent
|
||||||
| FileOperationEvent;
|
| FileOperationEvent;
|
||||||
|
|||||||
Reference in New Issue
Block a user