Replace FlashDecidedToContinueEvent with NextSpeakerCheckEvent (#5257)
This commit is contained in:
parent
3ef2c6d198
commit
23c014e29c
|
@ -43,8 +43,8 @@ import { ProxyAgent, setGlobalDispatcher } from 'undici';
|
||||||
import { DEFAULT_GEMINI_FLASH_MODEL } from '../config/models.js';
|
import { DEFAULT_GEMINI_FLASH_MODEL } from '../config/models.js';
|
||||||
import { LoopDetectionService } from '../services/loopDetectionService.js';
|
import { LoopDetectionService } from '../services/loopDetectionService.js';
|
||||||
import { ideContext } from '../ide/ideContext.js';
|
import { ideContext } from '../ide/ideContext.js';
|
||||||
import { logFlashDecidedToContinue } from '../telemetry/loggers.js';
|
import { logNextSpeakerCheck } from '../telemetry/loggers.js';
|
||||||
import { FlashDecidedToContinueEvent } from '../telemetry/types.js';
|
import { NextSpeakerCheckEvent } from '../telemetry/types.js';
|
||||||
|
|
||||||
function isThinkingSupported(model: string) {
|
function isThinkingSupported(model: string) {
|
||||||
if (model.startsWith('gemini-2.5')) return true;
|
if (model.startsWith('gemini-2.5')) return true;
|
||||||
|
@ -415,11 +415,15 @@ export class GeminiClient {
|
||||||
this,
|
this,
|
||||||
signal,
|
signal,
|
||||||
);
|
);
|
||||||
if (nextSpeakerCheck?.next_speaker === 'model') {
|
logNextSpeakerCheck(
|
||||||
logFlashDecidedToContinue(
|
|
||||||
this.config,
|
this.config,
|
||||||
new FlashDecidedToContinueEvent(prompt_id),
|
new NextSpeakerCheckEvent(
|
||||||
|
prompt_id,
|
||||||
|
turn.finishReason?.toString() || '',
|
||||||
|
nextSpeakerCheck?.next_speaker || '',
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
if (nextSpeakerCheck?.next_speaker === 'model') {
|
||||||
const nextRequest = [{ text: 'Please continue.' }];
|
const nextRequest = [{ text: 'Please continue.' }];
|
||||||
// This recursive call's events will be yielded out, but the final
|
// This recursive call's events will be yielded out, but the final
|
||||||
// turn object will be from the top-level call.
|
// turn object will be from the top-level call.
|
||||||
|
|
|
@ -163,6 +163,7 @@ export type ServerGeminiStreamEvent =
|
||||||
export class Turn {
|
export class Turn {
|
||||||
readonly pendingToolCalls: ToolCallRequestInfo[];
|
readonly pendingToolCalls: ToolCallRequestInfo[];
|
||||||
private debugResponses: GenerateContentResponse[];
|
private debugResponses: GenerateContentResponse[];
|
||||||
|
finishReason: FinishReason | undefined;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly chat: GeminiChat,
|
private readonly chat: GeminiChat,
|
||||||
|
@ -170,6 +171,7 @@ export class Turn {
|
||||||
) {
|
) {
|
||||||
this.pendingToolCalls = [];
|
this.pendingToolCalls = [];
|
||||||
this.debugResponses = [];
|
this.debugResponses = [];
|
||||||
|
this.finishReason = undefined;
|
||||||
}
|
}
|
||||||
// The run method yields simpler events suitable for server logic
|
// The run method yields simpler events suitable for server logic
|
||||||
async *run(
|
async *run(
|
||||||
|
@ -235,6 +237,7 @@ export class Turn {
|
||||||
const finishReason = resp.candidates?.[0]?.finishReason;
|
const finishReason = resp.candidates?.[0]?.finishReason;
|
||||||
|
|
||||||
if (finishReason) {
|
if (finishReason) {
|
||||||
|
this.finishReason = finishReason;
|
||||||
yield {
|
yield {
|
||||||
type: GeminiEventType.Finished,
|
type: GeminiEventType.Finished,
|
||||||
value: finishReason as FinishReason,
|
value: finishReason as FinishReason,
|
||||||
|
|
|
@ -18,7 +18,7 @@ import {
|
||||||
ApiErrorEvent,
|
ApiErrorEvent,
|
||||||
FlashFallbackEvent,
|
FlashFallbackEvent,
|
||||||
LoopDetectedEvent,
|
LoopDetectedEvent,
|
||||||
FlashDecidedToContinueEvent,
|
NextSpeakerCheckEvent,
|
||||||
SlashCommandEvent,
|
SlashCommandEvent,
|
||||||
} from '../types.js';
|
} from '../types.js';
|
||||||
import { EventMetadataKey } from './event-metadata-key.js';
|
import { EventMetadataKey } from './event-metadata-key.js';
|
||||||
|
@ -40,7 +40,7 @@ const api_error_event_name = 'api_error';
|
||||||
const end_session_event_name = 'end_session';
|
const end_session_event_name = 'end_session';
|
||||||
const flash_fallback_event_name = 'flash_fallback';
|
const flash_fallback_event_name = 'flash_fallback';
|
||||||
const loop_detected_event_name = 'loop_detected';
|
const loop_detected_event_name = 'loop_detected';
|
||||||
const flash_decided_to_continue_event_name = 'flash_decided_to_continue';
|
const next_speaker_check_event_name = 'next_speaker_check';
|
||||||
const slash_command_event_name = 'slash_command';
|
const slash_command_event_name = 'slash_command';
|
||||||
|
|
||||||
export interface LogResponse {
|
export interface LogResponse {
|
||||||
|
@ -512,12 +512,20 @@ export class ClearcutLogger {
|
||||||
this.flushIfNeeded();
|
this.flushIfNeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
logFlashDecidedToContinueEvent(event: FlashDecidedToContinueEvent): void {
|
logNextSpeakerCheck(event: NextSpeakerCheckEvent): void {
|
||||||
const data = [
|
const data = [
|
||||||
{
|
{
|
||||||
gemini_cli_key: EventMetadataKey.GEMINI_CLI_PROMPT_ID,
|
gemini_cli_key: EventMetadataKey.GEMINI_CLI_PROMPT_ID,
|
||||||
value: JSON.stringify(event.prompt_id),
|
value: JSON.stringify(event.prompt_id),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
gemini_cli_key: EventMetadataKey.GEMINI_CLI_RESPONSE_FINISH_REASON,
|
||||||
|
value: JSON.stringify(event.finish_reason),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
gemini_cli_key: EventMetadataKey.GEMINI_CLI_NEXT_SPEAKER_CHECK_RESULT,
|
||||||
|
value: JSON.stringify(event.result),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
gemini_cli_key: EventMetadataKey.GEMINI_CLI_SESSION_ID,
|
gemini_cli_key: EventMetadataKey.GEMINI_CLI_SESSION_ID,
|
||||||
value: this.config?.getSessionId() ?? '',
|
value: this.config?.getSessionId() ?? '',
|
||||||
|
@ -525,7 +533,7 @@ export class ClearcutLogger {
|
||||||
];
|
];
|
||||||
|
|
||||||
this.enqueueLogEvent(
|
this.enqueueLogEvent(
|
||||||
this.createLogEvent(flash_decided_to_continue_event_name, data),
|
this.createLogEvent(next_speaker_check_event_name, data),
|
||||||
);
|
);
|
||||||
this.flushIfNeeded();
|
this.flushIfNeeded();
|
||||||
}
|
}
|
||||||
|
|
|
@ -173,6 +173,16 @@ export enum EventMetadataKey {
|
||||||
|
|
||||||
// Logs the subcommand of the slash command.
|
// Logs the subcommand of the slash command.
|
||||||
GEMINI_CLI_SLASH_COMMAND_SUBCOMMAND = 42,
|
GEMINI_CLI_SLASH_COMMAND_SUBCOMMAND = 42,
|
||||||
|
|
||||||
|
// ==========================================================================
|
||||||
|
// Next Speaker Check Event Keys
|
||||||
|
// ===========================================================================
|
||||||
|
|
||||||
|
// Logs the finish reason of the previous streamGenerateContent response
|
||||||
|
GEMINI_CLI_RESPONSE_FINISH_REASON = 43,
|
||||||
|
|
||||||
|
// Logs the result of the next speaker check
|
||||||
|
GEMINI_CLI_NEXT_SPEAKER_CHECK_RESULT = 44,
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getEventMetadataKey(
|
export function getEventMetadataKey(
|
||||||
|
|
|
@ -13,8 +13,7 @@ export const EVENT_API_ERROR = 'gemini_cli.api_error';
|
||||||
export const EVENT_API_RESPONSE = 'gemini_cli.api_response';
|
export const EVENT_API_RESPONSE = 'gemini_cli.api_response';
|
||||||
export const EVENT_CLI_CONFIG = 'gemini_cli.config';
|
export const EVENT_CLI_CONFIG = 'gemini_cli.config';
|
||||||
export const EVENT_FLASH_FALLBACK = 'gemini_cli.flash_fallback';
|
export const EVENT_FLASH_FALLBACK = 'gemini_cli.flash_fallback';
|
||||||
export const EVENT_FLASH_DECIDED_TO_CONTINUE =
|
export const EVENT_NEXT_SPEAKER_CHECK = 'gemini_cli.next_speaker_check';
|
||||||
'gemini_cli.flash_decided_to_continue';
|
|
||||||
export const EVENT_SLASH_COMMAND = 'gemini_cli.slash_command';
|
export const EVENT_SLASH_COMMAND = 'gemini_cli.slash_command';
|
||||||
|
|
||||||
export const METRIC_TOOL_CALL_COUNT = 'gemini_cli.tool.call.count';
|
export const METRIC_TOOL_CALL_COUNT = 'gemini_cli.tool.call.count';
|
||||||
|
|
|
@ -15,7 +15,7 @@ import {
|
||||||
EVENT_TOOL_CALL,
|
EVENT_TOOL_CALL,
|
||||||
EVENT_USER_PROMPT,
|
EVENT_USER_PROMPT,
|
||||||
EVENT_FLASH_FALLBACK,
|
EVENT_FLASH_FALLBACK,
|
||||||
EVENT_FLASH_DECIDED_TO_CONTINUE,
|
EVENT_NEXT_SPEAKER_CHECK,
|
||||||
SERVICE_NAME,
|
SERVICE_NAME,
|
||||||
EVENT_SLASH_COMMAND,
|
EVENT_SLASH_COMMAND,
|
||||||
} from './constants.js';
|
} from './constants.js';
|
||||||
|
@ -27,7 +27,7 @@ import {
|
||||||
ToolCallEvent,
|
ToolCallEvent,
|
||||||
UserPromptEvent,
|
UserPromptEvent,
|
||||||
FlashFallbackEvent,
|
FlashFallbackEvent,
|
||||||
FlashDecidedToContinueEvent,
|
NextSpeakerCheckEvent,
|
||||||
LoopDetectedEvent,
|
LoopDetectedEvent,
|
||||||
SlashCommandEvent,
|
SlashCommandEvent,
|
||||||
} from './types.js';
|
} from './types.js';
|
||||||
|
@ -314,22 +314,22 @@ export function logLoopDetected(
|
||||||
logger.emit(logRecord);
|
logger.emit(logRecord);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function logFlashDecidedToContinue(
|
export function logNextSpeakerCheck(
|
||||||
config: Config,
|
config: Config,
|
||||||
event: FlashDecidedToContinueEvent,
|
event: NextSpeakerCheckEvent,
|
||||||
): void {
|
): void {
|
||||||
ClearcutLogger.getInstance(config)?.logFlashDecidedToContinueEvent(event);
|
ClearcutLogger.getInstance(config)?.logNextSpeakerCheck(event);
|
||||||
if (!isTelemetrySdkInitialized()) return;
|
if (!isTelemetrySdkInitialized()) return;
|
||||||
|
|
||||||
const attributes: LogAttributes = {
|
const attributes: LogAttributes = {
|
||||||
...getCommonAttributes(config),
|
...getCommonAttributes(config),
|
||||||
...event,
|
...event,
|
||||||
'event.name': EVENT_FLASH_DECIDED_TO_CONTINUE,
|
'event.name': EVENT_NEXT_SPEAKER_CHECK,
|
||||||
};
|
};
|
||||||
|
|
||||||
const logger = logs.getLogger(SERVICE_NAME);
|
const logger = logs.getLogger(SERVICE_NAME);
|
||||||
const logRecord: LogRecord = {
|
const logRecord: LogRecord = {
|
||||||
body: `Flash decided to continue.`,
|
body: `Next speaker check.`,
|
||||||
attributes,
|
attributes,
|
||||||
};
|
};
|
||||||
logger.emit(logRecord);
|
logger.emit(logRecord);
|
||||||
|
|
|
@ -266,15 +266,19 @@ export class LoopDetectedEvent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FlashDecidedToContinueEvent {
|
export class NextSpeakerCheckEvent {
|
||||||
'event.name': 'flash_decided_to_continue';
|
'event.name': 'next_speaker_check';
|
||||||
'event.timestamp': string; // ISO 8601
|
'event.timestamp': string; // ISO 8601
|
||||||
prompt_id: string;
|
prompt_id: string;
|
||||||
|
finish_reason: string;
|
||||||
|
result: string;
|
||||||
|
|
||||||
constructor(prompt_id: string) {
|
constructor(prompt_id: string, finish_reason: string, result: string) {
|
||||||
this['event.name'] = 'flash_decided_to_continue';
|
this['event.name'] = 'next_speaker_check';
|
||||||
this['event.timestamp'] = new Date().toISOString();
|
this['event.timestamp'] = new Date().toISOString();
|
||||||
this.prompt_id = prompt_id;
|
this.prompt_id = prompt_id;
|
||||||
|
this.finish_reason = finish_reason;
|
||||||
|
this.result = result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,5 +306,5 @@ export type TelemetryEvent =
|
||||||
| ApiResponseEvent
|
| ApiResponseEvent
|
||||||
| FlashFallbackEvent
|
| FlashFallbackEvent
|
||||||
| LoopDetectedEvent
|
| LoopDetectedEvent
|
||||||
| FlashDecidedToContinueEvent
|
| NextSpeakerCheckEvent
|
||||||
| SlashCommandEvent;
|
| SlashCommandEvent;
|
||||||
|
|
Loading…
Reference in New Issue